collections - 在迭代器上调用map时如何消除部分移动

标签 collections rust borrow-checker

我有一个简单的(我认为应该是)任务来处理 map 中包含的 Vec 值并生成另一个 Vec :

#[derive(Clone)]
struct Value(u32);
#[derive(Clone)]
struct Id(u32);

struct ValuesInfo {
    values: Vec<Value>,
    name: String,
    id: Id
}

struct ValueInfo{
    value: Value,
    name: String,
    id: Id
}

fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
    v.into_iter().map(|values_info|{
        values_info.values.into_iter().map(|value|{
            ValueInfo{
                value,
                name: values_info.name.clone(),
                id: values_info.id.clone()
            }
        }).collect::<Vec<ValueInfo>>()
    }).collect::<Vec<Vec<ValueInfo>>>()
}
Playground permalink
在这里我有一个部分移动错误看起来像
   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `values_info`
   --> src/lib.rs:20:44
    |
20  |         values_info.values.into_iter().map(|value|{
    |                            -----------     ^^^^^^^ value borrowed here after partial move
    |                            |
    |                            `values_info.values` moved due to this method call
...
23  |                 name: values_info.name.clone(),
    |                       ----------- borrow occurs due to use in closure
    |
note: this function consumes the receiver `self` by taking ownership of it, which moves `values_info.values`
    = note: move occurs because `values_info.values` has type `std::vec::Vec<Value>`, which does not implement the `Copy` trait

error: aborting due to previous error
我需要这个部分 move 因为这是任务的内容。是否有任何解决方法来解决该错误?

最佳答案

发生这种情况是因为闭包总是按名称捕获整个变量。因此传递给内部 map 的闭包将引用 values_info ,这是无效的,因为 values_info 已经部分移动(即使闭包不需要访问被移动的部分)。
RFC #2229 更改捕获以借用(或移动)闭包主体中所需的最小字段集。这将使原始代码按您的预期工作¹。但是,RFC 尚未实现。
相反,您可以手动完成:首先解构 ValuesInfo,然后只捕获闭包内的 nameid。你可以在得到 ValuesInfo 后立即对其进行解构,在外部闭包的参数列表中:

fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
    v.into_iter()
        .map(|ValuesInfo { values, name, id }| {
        //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ like `let ValuesInfo { values, name, id } = values_info;`
            values
                .into_iter()
                .map(|value| ValueInfo {
                    value,
                    name: name.clone(),
                    id: id.clone(),
                })
                .collect()
        })
        .collect()
}
也可以看看
  • How to use struct self in member method closure
  • HashMap borrow issue when trying to implement find or insert 使用类似的技巧解决。

  • ¹ 除非 ValuesInfo 实现 Drop ,否则会使任何解构或部分移动不健全。

    关于collections - 在迭代器上调用map时如何消除部分移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63962604/

    相关文章:

    rust - 为什么不能在同一结构中存储值和对该值的引用?

    rust - 如何实现支持可变迭代器的容器?

    rust - Rust 如何限制借用值的范围?

    java - 比较器排序

    java - Java Collections Framework 实现的 Big-O 总结?

    c# - 为整数键控模型集合寻找优雅/高效的解决方案

    static-libraries - Rust 静态库 "unlinked native library"警告

    windows - `cargo build` 失败并出现链接错误 "link.exe failed: exit code: 325595"

    rust - 如何将 C 可变长度数组代码转换为 Rust?

    c# - C# 有办法给我一个不可变的字典吗?