类型状态编程(Typestate Programming)
typestates的概念是指将有关对象当前状态的信息编码进该对象的类型中。虽然这听起来有点神秘,如果你在Rust中用过建造者模式,你就已经开始使用类型状态编程了!
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
对象,我们已经使用了一个基本的状态机。