Struct 如何最好地处理可以更改类型的结构字段

Struct 如何最好地处理可以更改类型的结构字段,struct,rust,Struct,Rust,我正在和一个图书馆合作,该图书馆使用锈蚀类型来跟踪状态。作为一个简化的示例,假设您有两个结构: struct FirstStruct {} struct SecondStruct {} impl FirstStruct { pub fn new() -> FirstStruct { FirstStruct {} } pub fn second(self) -> SecondStruct { SecondStruct {}

我正在和一个图书馆合作,该图书馆使用锈蚀类型来跟踪状态。作为一个简化的示例,假设您有两个结构:

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 {}
    }
}
要实际使用这些结构,您通常会遵循这样的模式,打印后您可能会保持第二种状态或返回第一种状态,具体取决于您使用库的方式:

fn main() {
    let first = FirstStruct::new();
    let second = first.second(); // consumes first
    second.print_something();
    // go back to default state
    let _first = second.first();
}
我想创建自己的结构,在内部处理状态更改并简化接口。这也让我有了一个可变的引用,可以传递给其他函数并调用print方法。使用它应该是这样的:

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()));
    }
}
enum结构状态{
第一(FirstStruct),
第二(第二结构),
}
结构组合结构{
国家:选择权,
}
impl组合结构{
pub fn new(第一个:FirstStruct)->CombinedStruct{
组合结构{
状态:一些(StructState::First(First)),
}
}
发布fn打印(&M自我){
让s=匹配self.state.take(){
一些=>匹配{
StructState::First(First)=>First.second(),
StructState::Second(Second)=>Second,
},
无=>恐慌!(),
};
s、 打印某物();
//如果我忘记这样做,那么我将失去对结构的访问权
//下一个电话会引起恐慌
self.state=Some(StructState::First(s.First());
}
}
我还没开始生锈,但我觉得这不太对劲。我不确定我是否缺少一个概念来简化这个问题,或者这个解决方案是否会随着我的应用程序变得更加复杂而导致所有权问题。有更好的方法吗


我曾经遇到过类似的问题,基本上同意您的解决方案,但我避免了
选项

也就是说,我基本上保留了你的

enum StructState {
    First(FirstStruct),
    Second(SecondStruct),
}
如果操作试图将
FirstStruct
转换为
SecondStruct
,我引入了一个函数
try\u to\u second
,大致如下所示:

impl StructState {
    fn try_to_second(self) -> Result<SecondState, StructState> {
        /// implementation
    }
}

同样,
Err
/
Ok
表示失败/成功,但在这种情况下,您在类型中编码了更具体的信息。

返回类型是否应该分别为
Result
Result
?成功时返回
SecondStruct
,失败时返回原始结构?为什么选择
self
而不是
&selt
&mut self
,为什么不实现
复制
impl FirstStruct {
    fn try_to_second(self) -> Result<FirstStruct, SecondStruct> {
        /// implementation
    }
}