20
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

なぜこうなった?解決するにはどうすればよいですか?

4

1 に答える 1

36

selfは type &mut Fooinprintを持っています。つまり、 type の値への借用された可変参照Fooです。Rust の型はデフォルトで所有権を移動します。つまり、何かを値で取得すると、ソースが静的に無効になり、プログラマーはそれを再度使用できなくなります (再初期化されない限り)。この場合、unwrap次の署名があります。

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

つまり、値ごとにOption値を取得しているため、その所有権を消費しようとしています。したがって、部分的に無効なデータを指しているままになるself.maybe_file.unwrap()データを消費しようとしています (その後でフィールドを使用することは違法です)。借用参照はどこでも指すことができるため、常に有効でなければならない借用参照でコンパイラがこれを強制する方法はないため、移動することは違法です。maybe_fileselfmaybe_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();

の代わりにfilehas typeがあるため、これは少し異なりますが、幸いなことに、コードの残りの部分に必要なのはこれだけです。&mut FileFile&mut File

これを機能させるもう 1 つの方法は、手動パターン マッチングを使用することです。

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

于 2015-01-19T23:10:45.757 に答える