无法从& mut self借用文件(错误消息:无法移出借来的内容)

时间:2015-01-19 22:31:46

标签: rust borrow-checker

use std::fs::File;
use std::io::Read;

pub struct Foo {
    maybe_file: Option<File>,
}

impl Foo {
    pub fn init(&mut self) {
        self.maybe_file = Some(File::open("/proc/uptime").unwrap());
    }

    pub fn print(&mut self) {
        let mut file = self.maybe_file.unwrap();
        let mut s = String::new();
        file.read_to_string(&mut s).unwrap();
        println!("Uptime: {}", s);
    }
}

fn main() {}

编译这将给我:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:14:24
   |
14 |         let mut file = self.maybe_file.unwrap();
   |                        ^^^^ cannot move out of borrowed content

为什么会这样?我该怎么做才能解决它?

1 个答案:

答案 0 :(得分:35)

self&mut Foo中的类型为print,也就是说,它是对类型Foo的值的借用可变引用。 Rust中的类型默认情况下移动所有权,也就是说,取值by-value将静态地使源无效并阻止程序员再次使用它(除非它被重新初始化)。在这种情况下,unwrap具有签名:

impl Option<T> {
    fn unwrap(self) -> T { ...

也就是说,它取值为Option值,因此试图消耗它的所有权。因此,self.maybe_file.unwrap()正在尝试使用maybe_file中的数据,这会使self指向部分无效的数据(之后使用maybe_file字段是非法的)。编译器无法使用借用的引用强制执行此操作,这些引用必须始终有效,因为它们可以指向任何地方,因此移出是非法的。

幸运的是,可以避免此问题:as_ref方法从Option<&T>中创建&Option<T>,而as_mut方法会创建Option<&mut T> &mut Option<T>。结果Option不再位于引用之后,因此通过unwrap使用它是合法的:

let mut file = self.maybe_file.as_mut().unwrap();

这略有不同,因为file的类型为&mut File而不是File,但幸运的是&mut File是其余代码所必需的。

另一种方法是使用手动模式匹配:

match self.maybe_file {
    Some(ref mut file)  => println!(...),
    None => panic!("error: file was missing")
}

这与.as_mut().unwrap()更加明确地完成相同的事情:ref mut创建一个直接指向self.maybe_file占用的内存的引用,就像as_mut一样}。