我有一些像这样的代码:
foo.move_right_by(10);
//do some stuff
foo.move_left_by(10);
最终我执行这两个操作非常重要,但我经常忘记在第一个之后执行第二个操作 . 它会导致很多错误,我想知道是否有一种习惯性的Rust方法来避免这个问题 . 当我忘记时,有没有办法让Rust编译器让我知道?
我的想法可能是某种类似的东西:
// must_use will prevent us from forgetting this if it is returned by a function
#[must_use]
pub struct MustGoLeft {
steps: usize;
}
impl MustGoLeft {
fn move(&self, foo: &mut Foo) {
foo.move_left_by(self.steps);
}
}
// If we don't use left, we'll get a warning about an unused variable
let left = foo.move_left_by(10);
// Downside: move() can be called multiple times which is still a bug
// Downside: left is still available after this call, it would be nice if it could be dropped when move is called
left.move();
有没有更好的方法来实现这一目标?
如果在没有调用该方法的情况下删除结构,则另一个想法是实现 Drop
和 panic!
. 这不是运行时检查,这是非常不受欢迎的 .
Edit: 我意识到我的例子可能太简单了 . 所涉及的逻辑可能变得非常复杂 . 例如,我们有这样的事情:
foo.move_right_by(10);
foo.open_box(); // like a cardboard box, nothing to do with Box<T>
foo.move_left_by(10);
// do more stuff...
foo.close_box();
请注意如何以良好的,正确嵌套的顺序执行操作 . 唯一重要的是事后总是调用逆操作 . 有时需要以某种方式指定顺序,以使代码按预期工作 .
我们甚至可以这样:
foo.move_right_by(10);
foo.open_box(); // like a cardboard box, nothing to do with Box<T>
foo.move_left_by(10);
// do more stuff...
foo.move_right_by(10);
foo.close_box();
foo.move_left_by(10);
// do more stuff...
3 回答
您可以使用幻像类型来携带附加信息,这些信息可用于类型检查而无需任何运行时成本 . 一个限制是
move_left_by
和move_right_by
必须返回一个新拥有的对象,因为它们需要更改类型,但通常这不会是一个问题 .此外,如果您不提供't actually use the types in your struct, so you have to add fields that use them. Rust' s
std
提供零大小的PhantomData
类型,编译器会抱怨为此目的 .您的约束可以像这样编码:
你可以像这样使用它:
如果您错过了所需的方法之一,
然后你会得到一个编译错误:
在这种情况下,我不认为
#[must_use]
真的是你想要的 . 这是解决问题的两种不同方法 . 第一个是在封闭中包含你需要做的事情,并抽象掉直接调用:第二种方法是创建一个包装类型,在删除时调用该函数(类似于
Mutex::lock
如何产生MutexGuard
,它在删除时解锁Mutex
):我只查看了最初的描述,可能错过了对话中的细节,但强制执行操作的一种方法是使用原始对象(向右)并将其替换为强制您向左移动相同数量的对象,然后才可以做任何你想做的事情来完成任务 .
新类型可以在进入完成状态之前禁止/要求进行不同的调用 . 例如(未经测试):
此时
foo
无法再向右移动,因为MustGoLeft
不允许,但它可以向左移动或打开框 . 如果它向左移动得足够远,它会再次回到CanGoRight
状态 . 但如果它打开盒子,则适用全新的规则 . 无论哪种方式,你都必须处理这两种可能性 .各州之间可能会有一些重复,但应该很容易重构 . 添加自定义特征可能会有所帮助 .
最后,听起来你正在制作各种各样的状态机 . 也许https://hoverbear.org/2016/10/12/rust-state-machine-pattern/会有用 .