1

假设我们定义了一个具有许多字段的通用结构,表示使用幻像类型的类型安全状态机:

struct Foo<State> {
    a: A,
    b: B,
    c: C,
    //...
    state: PhantomData<State>,
}

然后我们可以编写一个类型安全的状态转换:

impl Foo<SourceState> {
    fn transition(self, extra: X) -> Foo<DestinationState> {
        let Foo {a, b, c, state: _} = self;
        // do lots of stuff
        Foo { a, b, c, state: PhantomData } 
    }
}

但是我们需要笨拙地解开每个字段并以不同的结构重新打包。

我们也可以使用mem::transmute,尽管我的理解是同一结构的不同单态化不能保证具有相同的内存布局。

我希望这Foo { state: PhantomData, ..self }会奏效;唉,它无法编译。

有什么规范的、符合人体工程学的、安全的方法来写这个吗?

4

1 回答 1

2

没有办法以直接的方式做到这一点,因为它们是两种不同的类型:实际上,这就是你的代码的重点。为了简化它,我将分两步完成,第二步是通用转换:

use core::marker::PhantomData;

struct Foo<State> {
    a: i32,
    b: i32,
    c: i32,
    //...
    state: PhantomData<State>,
}

struct SourceState;
struct DestinationState;

impl<Src> Foo<Src> {
    fn transition<Dest>(self) -> Foo<Dest> {
        let Foo {a, b, c, state: _} = self;

        Foo { a, b, c, state: PhantomData } 
    }
}

impl Foo<SourceState> {
    fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
        // Do whatever you want with self

        self.transition()
    }
}

或者,您可以抽象出您有一个状态的事实:

mod stateful {
    use core::marker::PhantomData;

    pub struct Stateful<T, State> {
        pub data: T,
        state: PhantomData<State>,
    }

    impl<T, SrcState> Stateful<T, SrcState> {
        pub fn transform<DestState>(self) -> Stateful<T, DestState> {
            let Stateful { data, state: _ } = self;

            Stateful {
                data,
                state: Default::default(),
            }
        }
    }
}

struct Data {
    a: i32,
    b: i32,
    c: i32,
}

struct SourceState;
struct DestinationState;

type Foo<State> = stateful::Stateful<Data, State>;

impl Foo<SourceState> {
    fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
        // Do whatever you want with self.data

        self.transform()
    }
}
于 2020-02-17T16:49:19.393 回答