我有一个带有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
答案 0 :(得分:2)
更简单的解决方案是使用Option
来包装Reader
。
Option
有take
方法返回内容(并将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命名约定,state
和modify
来自Haskell的State
。