#move #container #state-machine #mutable #reference #moving #wrapper

no-std takeable

允许临时或永久地从容器中移动数据,或永久移动并使容器失效的容器类型

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数据结构

Download history 153/week @ 2024-03-13 421/week @ 2024-03-20 355/week @ 2024-03-27 311/week @ 2024-04-03 379/week @ 2024-04-10 446/week @ 2024-04-17 367/week @ 2024-04-24 207/week @ 2024-05-01 613/week @ 2024-05-08 654/week @ 2024-05-15 419/week @ 2024-05-22 713/week @ 2024-05-29 569/week @ 2024-06-05 830/week @ 2024-06-12 525/week @ 2024-06-19 722/week @ 2024-06-26

2,810 每月下载量

MIT/Apache-2.0/Unlicense

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<State>。暂时将其设置为 None 以移动状态。

  • 引入一个新的无效状态以实现相同的目的。

  • 使用 taketake_mut 包。

  • 重构你的代码以避免这个问题。

根据你的场景,这些选项中的任何一个可能都是首选。这个包提供了一个包装在 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。

无运行时依赖