Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
989 views
in Technique[技术] by (71.8m points)

rust - Can't borrow File from &mut self (error msg: cannot move out of borrowed content)

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() {}

Compiling this will give me:

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

Why is this happening? What do I do to solve it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

self has type &mut Foo in print, that is, it is a borrowed mutable reference to a value of type Foo. Types in Rust move ownership by default, that is, taking something by-value will statically invalidate the source and stop the programmer from using it again (unless it is reinitialized). In this case, unwrap has the signature:

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

That is, it is taking the Option value by-value and thus trying to consume ownership of it. Hence, self.maybe_file.unwrap() is trying to consume the data in maybe_file which would leave self pointing to partially invalid data (it is illegal to use the maybe_file field after that). There's no way the compiler can enforce this with borrowed references which have to be valid always as they could point anywhere, so it is illegal to move out.

Fortunately, one can avoid this problem: the as_ref method creates an Option<&T> out of an &Option<T> and the as_mut method creates an Option<&mut T> out of an &mut Option<T>. The resulting Option is then no longer behind a reference and so it is legal to consume it via unwrap:

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

This differs slightly because file has type &mut File instead of File, but fortunately &mut File is all that is necessary for the rest of the code.

Another approach to making this work is using manual pattern matching:

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

This is doing exactly the same thing as the .as_mut().unwrap() just more explicitly: the ref mut is create a reference pointing directly into the memory occupied by self.maybe_file, just like as_mut.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...