使用移动值,这是不可复制的[E0382] [E0277]

swi*_*end 2 iterator clone vector ownership rust

我有一个我不太了解的所有权问题.基本上我尝试在我的文件系统上创建一些硬链接,并在创建后删除它们.因此,我创建了一系列整数,我将其映射到我想要创建和销毁的实际文件名.我天真的解决方案看起来像这样:

use std::fs;

const src_file: &'static str = "a.txt";
const file_ext: &'static str = ".txt";

fn create_hardlink(dest_file: &str) {
    fs::hard_link(&src_file, &dest_file);
}

fn main() {

    let create = (0..10000).map(|x| x.to_string() + file_ext);
    let remove = (0..10000).map(|x| x.to_string() + file_ext);

    for file in create {
        create_hardlink(&file);
    }

    for file in remove {
        fs::remove_file(&file);
    }
}
Run Code Online (Sandbox Code Playgroud)

但我真正想要实现的是一个解决方案,我不必重复自己来创建带有文件名的静态集合,并且可以重用files第二个for循环:

...

fn main() {

    let files = (0..10000).map(|x| x.to_string() + file_ext);

    for file in files {
        create_hardlink(&file);
    }

    for file in files {
        fs::remove_file(&file);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以当我尝试这个时,编译器会抱怨,第二次使用files是不可能的,

src/main.rs:20:17: 20:22 error: use of moved value: `files` [E0382]
src/main.rs:20     for file in files {
Run Code Online (Sandbox Code Playgroud)

因为files已经进入了第一个for循环:

src/main.rs:16:17: 16:22 note: `files` moved here because it has type `core::iter::Map<core::ops::Range<i32>, [closure@src/main.rs:14:36: 14:64]>`, which is non-copyable
Run Code Online (Sandbox Code Playgroud)

在阅读完解释后,rustc --explain E0382我决定更改代码如下:

...

fn main() {

    let files = Rc::new(RefCell::new((0..10000).map(|x| x.to_string() + file_ext)));

    for file in files.clone() {
        create_hardlink(&file);
    }

    for file in files.clone() {
        fs::remove_file(&file);
    }
}
Run Code Online (Sandbox Code Playgroud)

但这不符合我的预期:

src/main.rs:16:5: 18:6 error: the trait `core::iter::Iterator` is not implemented for the type `alloc::rc::Rc<core::cell::RefCell<core::iter::Map<core::ops::Range<_>, [closure@src/main.rs:14:53: 14:81]>>>` [E0277]
src/main.rs:16     for file in files.clone() {
src/main.rs:17         create_hardlink(&file);
src/main.rs:18     }
note: in expansion of for loop expansion
src/main.rs:16:5: 18:6 note: expansion site
src/main.rs:16:5: 18:6 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:16:5: 18:6 note: `alloc::rc::Rc<core::cell::RefCell<core::iter::Map<core::ops::Range<_>, [closure@src/main.rs:14:53: 14:81]>>>` is not an iterator; maybe try calling `.iter()` or a similar method
src/main.rs:16     for file in files.clone() {
src/main.rs:17         create_hardlink(&file);
src/main.rs:18     }
note: in expansion of for loop expansion
src/main.rs:16:5: 18:6 note: expansion site
src/main.rs:16:5: 18:6 note: required by `core::iter::IntoIterator::into_iter`
src/main.rs:16     for file in files.clone() {
src/main.rs:17         create_hardlink(&file);
src/main.rs:18     }
Run Code Online (Sandbox Code Playgroud)

我能做什么?我是否真的必须实现类似告诉我core::iter::Iterator的类型?我希望不是...alloc::rc::Rc<core::cell::RefCell<core::iter::Map<core::ops::Range<_>rustc --explain E0277

是否有一个简单的解决方案,如files静态定义staticconst?或者我的方法是映射Range非生锈?

为什么我有类似的类型<core::iter::Map<core::ops::Range<_>而不是类似的类型<core::iter::String>

我希望你能帮助我解决这个问题,并向我这样的新手启发Rust所有权原则.

fil*_*mor 5

据我所知,Rust迭代器只是前向迭代器,所以它们只能迭代一次.您可以将collect它们放入向量中或使用函数生成迭代器:

// 1st option
let files: Vec<_> = (0..10000).map(|x| x.to_string() + file_ext).collect();

for f in &files { ... } // Borrow `files`

// 2nd option
let files = || (0..10000).map(|x| x.to_string() + file_ext);

for f in files() { ... } // Call the closure to get an iterator
Run Code Online (Sandbox Code Playgroud)

  • 但是第一个将同时分配所有内存,具体取决于可能不太好的文件数量. (2认同)