Reputation: 26110
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.
Upvotes: 0
Views: 2423
Reputation: 171
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?
Upvotes: 4