简体   繁体   中英

Rust: why do I get error [E0507]: cannot move out of `files.input_file` which is behind a shared reference

I have narrowed down my real life Rust code to the following:

use std::fs::File;
use std::io::{BufRead, BufReader};

struct FileHandler {
    input_file: File,
}

impl FileHandler {
    fn setup(in_file_name: &str) -> Self {
        let i_file = File::open(in_file_name).unwrap();
        Self { input_file: i_file }
    }
}

fn process_file(files: &FileHandler) {
    let lines = BufReader::new(files.input_file).lines();
    for _ln in lines {
        println!("one more line");
    }
}

fn main() {
    let files = FileHandler::setup("foo.txt");
    process_file(&files);
}

It does not compile with the message:

cannot move out of `files.input_file` which is behind a shared reference
  --> demo.rs:16:32
   |
16 |     let lines = BufReader::new(files.input_file).lines();
   |                                ^^^^^^^^^^^^^^^^ move occurs because `files.input_file` has type `File`, which does not implement the `Copy` trait

But precisely, I don't want to make a copy. I just want to use the file I have already checked to be correct. I have tried with mutable references and fields. Same error.

As the error implies, BufReader::new is attempting to move files.input_files , which is behind a shared reference ( &FileHandler ). In order to have it not move files.input_file , use a reference to it instead:

use std::fs::File;
use std::io::{BufRead, BufReader};

struct FileHandler {
    input_file: File,
}

impl FileHandler {
    fn setup(in_file_name: &str) -> Self {
        let i_file = File::open(in_file_name).unwrap();
        Self { input_file: i_file }
    }
}

fn process_file(files: &FileHandler) {
    // --- CHANGED ---
    let lines = BufReader::new(&files.input_file).lines();

    for _ln in lines {
        println!("one more line");
    }
}

fn main() {
    let files = FileHandler::setup("foo.txt");
    process_file(&files);
}

This happens because BufReader is generic. If you give it a value, it will move it, if you give it a reference it'll just use the reference instead. Take a look at " Understanding Ownership " from The Book for more information on how ownership works.

let files = FileHandler::setup("foo.txt");

This creates a FileHandler struct which stores another struct called File in input_file property.

files struct has the ownership of it's properties. So files owns input_file .

If you directly use that input_file property like this:

some_function(files.input_file);

This means input_file 's ownership will be moved to that function.

But if you do this then what happens if I try to access files.input_file again? Maybe inside of some_function , the struct stored in input_file property destroyed?

So I can't use it anymore like files.input_file .


Solution:

Use the reference of input_file , so it is borrowed , not moved :

some_function(&files.input_file);

Or in this case of yours:

BufReader::new(&files.input_file);

(btw IMHO I can suggest that you can use new instead of setup . Creating a struct with some settings often managed by a new function. FileHandler::new() is much more familiar to Rust devs. Like BufReader::new() )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM