简体   繁体   中英

Rust: move occurs because has type `ReadDir`, which does not implement the `Copy` trait

In https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html I find very similar example of using references for String type, but in my code I got move occurs because `*paths_ref` has type `ReadDir`, which does not implement the `Copy` trait . What difference with String ? How I can use ReadDir without memcopy there?

use std::fs;

const CACHE_ADDR: &str = ".";

fn get_files() -> std::fs::ReadDir {
    fs::read_dir(CACHE_ADDR).unwrap()
}

fn main() {
    let paths: std::fs::ReadDir = get_files();
    let paths_ref = &paths;
    println!("Count: {}", paths_ref.count());
    for path in paths_ref.into_iter() {
        println!("{:?}", path.unwrap().path());
        break;
    }
}

cargo build error:

error[E0507]: cannot move out of `*paths_ref` which is behind a shared reference
 --> src/main.rs:8:27
  |
8 |     println!("Count: {}", paths_ref.count());
  |                           ^^^^^^^^^ move occurs because `*paths_ref` has type `ReadDir`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `*paths_ref` which is behind a shared reference
 --> src/main.rs:9:17
  |
9 |     for path in paths_ref.into_iter() {
  |                 ^^^^^^^^^ move occurs because `*paths_ref` has type `ReadDir`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0507`.
error: could not compile `osm-nca-proc`

To learn more, run the command again with --verbose.

The function fn calculate_length(s: &String) -> usize takes a reference of String and returns an usize , in this case, you own the returned value. When you do println.("The length of '{}' is {},", s1; len); , your println macro trying to use s1 and len . There are no problem with this.

In your function, fn get_files() -> std::fs::ReadDir return a ReadDir struct, which you have the ownership of this struct, which is okay.

In the following line, you are creating a immutable reference to it let paths_ref = &paths; , this is okay.

In the line after that, you are trying to call paths_ref.count() , this is not okay. Why? count is a method belong to trait Iterator , if you look at the definition of count method in Iterator, which is pub fn count(self) -> usize , it takes the ownership of self , and then return a usize . What this means is that as soon as you call count , the Iterator is consumed and not exist anymore.

Because path_ref is a reference of self , and it doesn't own the ReadDir data, you cannot call on count on it. You can use paths.count() which will consume the paths variable and return a usize. But note after you call count your paths variable will not exist anymore and you can't use it in the below context.

In your example, you essentially need to iterate the ReadDir twice, one is to get the total count, and the other is to iterate the each element. You can achieve the same thing by using 1 iteration and manually count the total element (like using a counter i += 1 in each iteration), or you can call get_files twice.

In the case you really want to iterate once, you can collect it (into a vec) and then you can use it to get the length and get iteration.

I found a very similar stackoverflow question, you might want to check this one How to use the same iterator twice, once for counting and once for iteration?

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