类型状态编程(Typestate Programming)
typestates的概念是指将有关对象当前状态的信息编码进该对象的类型中。虽然这听起来有点神秘,如果你在Rust中用过https://doc.rust-lang.org/1.0.0/style/ownership/builders.html)[建造者模式],你就已经开始使用类型状态编程了!
pub mod foo_module {
#[derive(Debug)]
pub struct Foo {
inner: u32,
}
pub struct FooBuilder {
a: u32,
b: u32,
}
impl FooBuilder {
pub fn new(starter: u32) -> Self {
Self {
a: starter,
b: starter,
}
}
pub fn double_a(self) -> Self {
Self {
a: self.a * 2,
b: self.b,
}
}
pub fn into_foo(self) -> Foo {
Foo {
inner: self.a + self.b,
}
}
}
}
fn main() {
let x = foo_module::FooBuilder::new(10)
.double_a()
.into_foo();
println!("{:#?}", x);
}在这个例子里,不能直接生成一个Foo对象。必须先生成一个FooBuilder,并且恰当地初始化FooBuilder后,才能获取到需要的Foo对象。
这个最小的例子编码了两个状态:
FooBuilder,其表示一个“没有被配置”,或者“正在配置”状态Foo,其表示了一个“被配置”,或者“可以使用”状态。
强类型
因为Rust有一个强类型系统,没有什么简单的方法可以奇迹般地生成一个Foo实例,也没有简单的方法可以不用调用into_foo()方法而把一个FooBuilder变成一个Foo。另外,调用into_foo()方法消费了最初的FooBuilder结构体,意味着不生成一个新的实例就不能被再次使用它。
这允许我们可以将系统的状态表示成类型,把状态转换必须的动作包括进转换两个类型的方法中。通过生成一个 FooBuilder,转换成一个 Foo 对象,我们已经使用了一个基本的状态机。