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

Collections 在迭代器上调用map时如何消除部分移动,collections,rust,borrow-checker,Collections,Rust,Borrow Checker,我有一个简单的任务(我认为应该是)映射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, i

我有一个简单的任务(我认为应该是)映射
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>>>()
}
#[派生(克隆)]
结构值(u32);
#[衍生(克隆)]
结构Id(u32);
结构值信息{
价值观:Vec,
名称:String,
id:id
}
结构值信息{
价值:价值,
名称:String,
id:id
}
fn扩展_值(v:Vec)->Vec{
v、 进入_iter().map(|值_信息|{
值_info.values.into_iter().map(| value|{
ValueInfo{
价值
名称:values\u info.name.clone(),
id:values\u info.id.clone()
}
})收集::()
})收集::()
}

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

   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
编译操场v0.0.1(/playerd)
错误[E0382]:移动值的借用:`values\u info`
-->src/lib.rs:20:44
|
20 | values|info.values.into_iter().map(| value|{
|------------^^^^^^部分移动后在此借用的值
|                            |
|`values_info.values`由于此方法调用而移动
...
23 | name:values_info.name.clone(),
|------因在关闭时使用而发生借用
|
注意:此函数通过获取接收者“self”的所有权来消耗接收者“self”,从而移动“values\u info.values”`
=注意:发生移动是因为'values\u info.values'的类型为'std::vec::vec',而该类型不实现'Copy'特性
错误:由于上一个错误而中止

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

发生这种情况是因为闭包总是按名称捕获整个变量。因此传递到内部
映射的闭包将引用
值信息
,这是无效的,因为
值信息
o
已部分移动(即使封盖不需要访问已移动的零件)

更改捕获以借用(或移动)闭包正文中所需的最小字段集。这将使原始代码按预期工作。但是,RFC尚未实现


相反,您可以手动执行此操作:首先分解
ValuesInfo
,并仅在闭包内捕获
name
id
。您可以在获得
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()
}
fn扩展_值(v:Vec)->Vec{
v、 进入()
.map(| ValuesInfo{values,name,id}|{
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^类似“let ValuesInfo{values,name,id}=values\u info”`
价值观
.into_iter()
.map(|值|值信息{
价值
名称:name.clone(),
id:id.clone(),
})
.collect()
})
.collect()
}
另见
  • 使用类似的技巧解决了这个问题


除非
ValuesInfo
执行
Drop
,这会使任何解构或部分移动不可靠。

闭包中的命名
值\u信息将借用它
作为一个整体,尽管它已经部分移动了
(如错误消息所述)。
你应该事先借用你需要的会员

let name=&values\u info.name;
let id=&values\u info.id;
值_info.values.into_iter().map(| value|{
ValueInfo{
价值
名称:name.clone(),
id:id.clone(),
}
#[派生(克隆)]//您可以派生副本。u32通常复制成本较低
结构值(u32);
#[派生(克隆)]//您可以派生副本
结构Id(u32);
结构值信息{
价值观:Vec,
名称:String,
id:id
}
结构值信息{
价值:价值,
名称:String,
id:id
}
//不需要消费v。不确定它是否会派上用场
fn扩展_值(v:&Vec)->Vec{
//仅当您需要阵列内容的所有权时,才使用into_iter
//我认为您不需要,因为您正在克隆ValueInfo的每一个值
//除了已经准备好复制/克隆的值之外
v、 iter().map(|值|信息|{
values_info.values.iter().map(| value|{
ValueInfo{
value:value.clone(),
名称:values\u info.name.clone(),
id:values\u info.id.clone()
}
})收集::()
})收集::()
}
这就是说,如果你真的不想复制/克隆
Value
,你需要
clone
name和
id
。编译器会阻止你使用
values\u info.name.clone()
,因为函数
已经消耗到
values\u info
。 如果您确实不想复制
Value

#[派生(克隆)]
结构值(u32);
#[衍生(克隆)]
结构Id(u32);
结构值信息{
价值观:Vec,
名称:String,
id:id
}
结构值信息{
价值:价值,
名称:String,
id:id
}
fn扩展_值(v:Vec)->Vec{
v、 进入_iter().map(|值_信息|{
让name=values_info.name.clone();
让id=values_info.id.clone();
值\u info.values.into\u iter().map(
|价值|{
ValueInfo{
价值
名称:name.clone(),
id:id.clone(),
}
})收集::()
})收集::()
}

name
id
被克隆两次。第一次克隆可以通过不可变的借用来避免。你不能借用
name
id
并在调用
后使用它们。
此时的值信息
被消耗。我的方法看起来与你的方法非常相似。
克隆的数量呼叫