如何解决在迭代器上调用地图时如何消除部分移动
我有一个简单的(我认为应该是)任务,可以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,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>>>()
}
在这里我有一个局部移动错误,看起来像
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
,然后仅在闭包内部捕获name
和id
。您可以在外部闭包的参数列表中一经获取ValuesInfo
即可对其进行破坏:
fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
v.into_iter()
.map(|ValuesInfo { values,name,id }| {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ like `let ValuesInfo { values,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
,否则将造成破坏性破坏或部分移动。
在闭包中命名values_info
会借用它
整体来看,尽管它已经部分移动了
(如错误消息所示)。
您应该事先借用所需的成员。
let name=&values_info.name;
let id=&values_info.id;
values_info.values.into_iter().map(|value|{
ValueInfo{
value,}
,
#[derive(Clone)] //you could derive Copy. u32 is generally cheap to copy
struct Value(u32);
#[derive(Clone)] //you could derive Copy
struct Id(u32);
struct ValuesInfo {
values: Vec<Value>,name: String,id: Id
}
struct ValueInfo{
value: Value,id: Id
}
//No need to consume v. Not sure if it will come in handy
fn extend_values(v: &Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
//Use into_iter only if you need the ownership of the content of the array
// which I don't think you need because you are cloning every value of ValueInfo
//except for value which is already cheep to copy/clone
v.iter().map(|values_info|{
values_info.values.iter().map(|value|{
ValueInfo{
value: value.clone(),name: values_info.name.clone(),id: values_info.id.clone()
}
}).collect::<Vec<ValueInfo>>()
}).collect::<Vec<Vec<ValueInfo>>>()
}
也就是说,如果您真的不想复制/克隆Value
,则需要先输入clone
的名称和id
。编译器使您无法使用values_info.name.clone()
,因为函数into_iter
已消耗values_info
。
如果您确实不想复制Value
#[derive(Clone)]
struct Value(u32);
#[derive(Clone)]
struct Id(u32);
struct ValuesInfo {
values: Vec<Value>,id: Id
}
fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
v.into_iter().map(|values_info|{
let name = values_info.name.clone();
let id = values_info.id.clone();
values_info.values.into_iter().map(
|value| {
ValueInfo{
value,}
}).collect::<Vec<ValueInfo>>()
}).collect::<Vec<Vec<ValueInfo>>>()
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。