4 个版本
使用旧的 Rust 2015
0.2.2 | 2022年11月6日 |
---|---|
0.2.1 | 2022年10月26日 |
0.2.0 | 2017年8月5日 |
0.1.0 | 2017年7月22日 |
#1060 在 数据结构
2,810 每月下载量
13KB
147 行
Takeable
一个简单的包装类型,它只包含需要从可变引用中移动的值。
文档
有时,临时或永久地移动出可变引用是有用的。例如,在处理使用枚举实现的状态机时,这种情况经常发生。例如,假设你有一个以下状态机
enum State {
Starting,
Running(Resource1, Resource2),
Finished(Option<Resource2>)
}
假设你想实现一个将状态从 Running
更改为 Finished
的函数。简单的方法可能是
pub fn to_finished(state: &mut State) {
let newstate = match *state {
State::Starting => State::Finished(None),
State::Running(_, r) => State::Finished(Some(r)),
State::Finished(r) => State::Finished(r),
};
*state = newstate;
}
然而,这会导致“无法从借用内容中移动”的错误。
解决这个问题有几个方法
根据你的场景,这些选项中的任何一个可能都是首选。这个包提供了一个包装在 Option<T>
中的包装器,它具有强制正确使用 Option
的 API。这种方法还有优点,即它允许在不检查枚举标记之外进行性能优化。
使用这个库,代码可以写成这样
struct StateMachine(Takeable<State>);
enum State {
Starting,
Running(Resource1, Resource2),
Finished(Option<Resource2>)
}
pub fn to_finished(state: &mut StateMachine) {
state.0.borrow(|state| {
match state {
State::Starting => State::Finished(None),
State::Running(_, r) => State::Finished(Some(r)),
State::Finished(r) => State::Finished(r),
}
});
}
有时,即使只有一个可变引用,永久性地移动一个值也可能很有用。这样的用例之一是在实现drop
时需要调用一个消耗字段的字段的方法。可以使用这个crate来完成,如下所示
struct Resource;
impl Resource {
pub fn close(self) {}
}
struct ResourceUser {
resource: Takeable<Resource>;
}
impl Drop for ResourceUser {
fn drop(&mut self) {
self.resource.take().close();
}
}
上述代码也可以通过直接使用Option
而不是Takeable
来实现。然而,后者有这样一个优点,即通过其类型可以清楚地看出它必须始终有一个值,并且在访问其他地方的Resource
时不需要处理None
变体。相反,如果尝试在值被移出之后执行此操作,Takeable
将引发panic。