如何在结构中捕获自耗变量?

时间:2016-10-05 18:34:49

标签: struct rust

我有一个带有consumes the Reader and returns a Writer方法的Reader实例,而Writer可以再次回到Reader。使用不可变性是微不足道的,但我无法弄清楚如何隐藏来自呼叫者的不变性,只是让读者 - 作者 - 读者在幕后用可变的自我跳舞。

基本上我喜欢这样的东西:

struct Container<'a> {
    reader: Reader<'a, File>
}

fn update(&mut self) {
    let writer = self.reader.as_writer();
    writer.write_something();
    self.reader = writer.as_reader();
}

只会出现cannot move out of borrowed content错误。试图在Reader周围添加Box,Cell或RefCell,这只会导致其他错误。

reader可以隐藏在可变接口后面还是强制整个结构层次结构也是可变的? (即类似于Haskell中的IO)

自包含的样本,其类型与真实内容相匹配(我认为)

#[derive(Debug)]
struct NoCopy(u32);

#[derive(Debug)]
struct Flipper<'a, T: 'a> {
    data: &'a mut T,
}
#[derive(Debug)]
struct Flopper<'a, T: 'a> {
    data: &'a mut T,
}
impl<'a, T> Flipper<'a, T> {
    fn flip(self) -> Flopper<'a, T> {
        Flopper{data: self.data}
    }
}
impl<'a, T> Flopper<'a, T> {
    fn flop(self) -> Flipper<'a, T> {
        Flipper{data: self.data}
    }
}

#[derive(Debug)]
struct Container<'a, T: 'a> {
    flipper: Flipper<'a, T>,
}
impl<'a, T> Container<'a, T> {
    fn run(&mut self) {
        self.flipper = self.flipper.flip().flop();
    }
}

fn main() {
    let f = Flipper{data: &mut NoCopy(42)};
    let f = f.flip().flop();
    println!("f={:?}", f);

    let mut c = Container{flipper: f};
    c.run();
    println!("c={:?}", c);
}
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:29:24
   |
29 |         self.flipper = self.flipper.flip().flop();
   |                        ^^^^ cannot move out of borrowed content

2 个答案:

答案 0 :(得分:2)

更简单的解决方案是使用Option来包装Reader

Optiontake方法返回内容(并将None放入Option),然后您可以将Reader放回去分配

struct Container<'a> {
    reader: Option<Reader<'a, File>>
}

fn update(&mut self) {
    let writer = self.reader.take().unwrap().as_writer();
                             ^~~~~~~
    writer.write_something();
    self.reader = Some(writer.as_reader());
                  ^~~~~                  ^
}

答案 1 :(得分:0)

Matthieu's answer为基础我认为在Option周围添加一个(普通的)包装器可以直接执行编译时检查,只允许&#34;借用&#34; Reader实例虽然需要另一个实例,但之后会返回。

struct State<T>(Option<T>);

impl<T> State<T> {
    pub fn new(val: T) -> Self {
        State(Some(val))
    }
    pub fn modify<F>(&mut self, fun: F)
        where F: FnOnce(T) -> T
    {
        self.0 = Some(fun(self.0.take().unwrap()));
    }
}

用法:

fn modify(&mut self) {
    self.state.modify(|reader| {
        let writer = reader.as_writer();
        writer.write_something();
        writer.as_reader()
    }
}

应该足够好以避免意外滥用。虽然不知道panic!放卷。

可能不遵循Rust命名约定,statemodify来自Haskell的State