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

St.*_*rio 4 collections rust borrow-checker

我有一个简单的(我认为应该是)任务来处理mapa 中包含的值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>>>()
}
Run Code Online (Sandbox Code Playgroud)

游乐场永久链接

在这里我有一个部分移动错误看起来像

   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
Run Code Online (Sandbox Code Playgroud)

我需要这个部分,move因为这就是任务的内容。是否有任何解决方法来解决该错误?

tre*_*tcl 6

发生这种情况是因为闭包总是按名称捕获整个变量。因此传递给内部的闭包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()
}
Run Code Online (Sandbox Code Playgroud)

也可以看看


¹ 除非ValuesInfoimplements Drop,这会使任何解构或部分移动不健全。