3 ms·
The cited post[1] recommends an enum for this job, which avoids the dynamic dispatch and makes it easier to get at a specific state’s data when you have the who
by kd5bjo 7y ago
The cited post[1] recommends an enum for this job, which avoids the dynamic dispatch and makes it easier to get at a specific state’s data when you have the whole machine.
[1] https://hoverbear.org/blog/rust-state-machine-pattern/ https://hoverbear.org/blog/rust-state-machine-pattern/
- cerebellum42 7y agoThat is probably the way to go, agreed.
- papaf 7y agoI am not a fan of the hoverbear state machine pattern. I find that it makes simple things complicated and hard things impossible. I used it and I had problems with: - Reusing code between states. - Making callbacks to other APIs during state changes. I ended up using the standard state pattern described here: https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.ht... The state pattern is not considered to be idiomatic Rust, but in my experience it works better and is very flexible. The state pattern has the downside that the type system does not enforce which state changes are allowed.
- jstrong 7y agofor reusing code between states, did you try impl blocks that are generic over the state type parameter? for struct State<T> { state: T } with possible states struct A { id: Uuid } struct B { id: Uuid } use a trait trait HasId { fn id_mut(&mut self) -> &mut Uuid; } now you can impl over both A and B impl<T: HasId> for State<T> { fn new_id(&mut self) { *self.state.id_mut() = Uuid::new_v4() } } simplistic example but enough to communicate the idea hopefully. generally, macros makes this kind of thing ergonomic so you can generate the trait implementations and so on. otherwise it's a lot of typing. don't understand what you mean about making callbacks to other APIs during transitions.
- papaf 7y agoI did not try that -- its a cool technique. Thanks for taking the time to share it.