是否有一种安全、符合人体工程学的方法来更改复杂结构中的幻像类型?
Is there a safe, ergonomic way to change a phantom type in a complex struct?
假设我们定义了一个泛型结构,有很多字段,代表一个使用虚类型的类型安全状态机:
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 }
能奏效;唉,编译失败。
有什么规范的、符合人体工程学的、安全的方法来写这个吗?
没有办法以直接的方式做到这一点,因为它们是两种不同的类型:实际上,这就是您的代码的全部意义所在。为了简化它,我将分两步进行,第二步是通用转换:
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()
}
}
假设我们定义了一个泛型结构,有很多字段,代表一个使用虚类型的类型安全状态机:
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 }
能奏效;唉,编译失败。
有什么规范的、符合人体工程学的、安全的方法来写这个吗?
没有办法以直接的方式做到这一点,因为它们是两种不同的类型:实际上,这就是您的代码的全部意义所在。为了简化它,我将分两步进行,第二步是通用转换:
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()
}
}