Я работаю с библиотекой, которая использует типы Rust для отслеживания состояния. В качестве упрощенного примера, скажем, у вас есть две структуры:
struct FirstStruct {}
struct SecondStruct {}
impl FirstStruct {
pub fn new() -> FirstStruct {
FirstStruct {}
}
pub fn second(self) -> SecondStruct {
SecondStruct {}
}
// configuration methods defined in this struct
}
impl SecondStruct {
pub fn print_something(&self) {
println!("something");
}
pub fn first(self) -> FirstStruct {
FirstStruct {}
}
}
И для фактического использования этих структур вы обычно следуете шаблону, подобному такому, после печати вы можете остаться во втором состоянии или go вернуться в первое состояние в зависимости от того, как вы используете библиотеку:
fn main() {
let first = FirstStruct::new();
let second = first.second(); // consumes first
second.print_something();
// go back to default state
let _first = second.first();
}
Я хочу создать свою собственную структуру, которая обрабатывает изменения состояния внутри и упрощает интерфейс. Это также позволяет мне иметь единственную изменяемую ссылку вокруг, которую я могу передать другим функциям и вызвать метод печати. Его использование должно выглядеть примерно так:
fn main() {
let mut combined = CombinedStruct::new(FirstStruct::new());
combined.print();
}
Я нашел следующее решение, которое работает, по крайней мере, в этом упрощенном примере:
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
struct CombinedStruct {
state: Option<StructState>,
}
impl CombinedStruct {
pub fn new(first: FirstStruct) -> CombinedStruct {
CombinedStruct {
state: Some(StructState::First(first)),
}
}
pub fn print(&mut self) {
let s = match self.state.take() {
Some(s) => match s {
StructState::First(first) => first.second(),
StructState::Second(second) => second,
},
None => panic!(),
};
s.print_something();
// If I forget to do this, then I lose access to my struct
// and next call will panic
self.state = Some(StructState::First(s.first()));
}
}
Я все еще довольно плохо знаком с Rust, но мне это не кажется правильным. Я не уверен, есть ли какая-то концепция, которая мне не хватает, которая могла бы упростить это или это решение могло бы привести к проблемам владения, поскольку мое приложение усложнялось. Есть ли лучший способ сделать это?
Playground link