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

klr1opcd  于 2022-11-12  发布在  其他
关注(0)|答案(3)|浏览(182)

我有一个简单的(我认为应该是)任务将map的值包含在一个Vec中并产生另一个Vec

  1. # [derive(Clone)]
  2. struct Value(u32);
  3. # [derive(Clone)]
  4. struct Id(u32);
  5. struct ValuesInfo {
  6. values: Vec<Value>,
  7. name: String,
  8. id: Id
  9. }
  10. struct ValueInfo{
  11. value: Value,
  12. name: String,
  13. id: Id
  14. }
  15. fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
  16. v.into_iter().map(|values_info|{
  17. values_info.values.into_iter().map(|value|{
  18. ValueInfo{
  19. value,
  20. name: values_info.name.clone(),
  21. id: values_info.id.clone()
  22. }
  23. }).collect::<Vec<ValueInfo>>()
  24. }).collect::<Vec<Vec<ValueInfo>>>()
  25. }

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

  1. Compiling playground v0.0.1 (/playground)
  2. error[E0382]: borrow of moved value: `values_info`
  3. --> src/lib.rs:20:44
  4. |
  5. 20 | values_info.values.into_iter().map(|value|{
  6. | ----------- ^^^^^^^ value borrowed here after partial move
  7. | |
  8. | `values_info.values` moved due to this method call
  9. ...
  10. 23 | name: values_info.name.clone(),
  11. | ----------- borrow occurs due to use in closure
  12. |
  13. note: this function consumes the receiver `self` by taking ownership of it, which moves `values_info.values`
  14. = note: move occurs because `values_info.values` has type `std::vec::Vec<Value>`, which does not implement the `Copy` trait
  15. error: aborting due to previous error

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

lb3vh1jj

lb3vh1jj1#

在2018版的Rust中,闭包总是通过变量名来捕获整个变量,所以传递给内部map的闭包将引用values_info,这是无效的,因为values_info已经被部分移动了(即使闭包不需要访问被移动的部分)。
rust 色2021+
自Rust 2021以来,只捕获闭包主体中所需的最小字段集。这使得原始代码能够按预期工作¹,因此您可以通过简单的changing the playground edition to 2021来消除错误。更多信息请参见edition guide
2015年和2018年生 rust
在以前的版本中,您可以手动执行此操作:首先反构ValuesInfo *,只捕获闭包内部的nameid。一旦得到ValuesInfo,就可以在外部闭包的参数列表中反构它:

  1. fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
  2. v.into_iter()
  3. .map(|ValuesInfo { values, name, id }| {
  4. // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ like `let ValuesInfo { values, name, id } = values_info;`
  5. values
  6. .into_iter()
  7. .map(|value| ValueInfo {
  8. value,
  9. name: name.clone(),
  10. id: id.clone(),
  11. })
  12. .collect()
  13. })
  14. .collect()
  15. }

另请参阅

¹除非ValuesInfo实现了Drop,这使得任何解构或部分移动都不健全。

展开查看全部
tpgth1q7

tpgth1q72#

在闭包中命名values_info将借用它作为一个整体,尽管它已经被部分移动了(正如错误消息所告诉的)。

  1. let name=&values_info.name;
  2. let id=&values_info.id;
  3. values_info.values.into_iter().map(|value|{
  4. ValueInfo{
  5. value,
  6. name: name.clone(),
  7. id: id.clone(),
  8. }
xuo3flqw

xuo3flqw3#

  1. # [derive(Clone)] //you could derive Copy. u32 is generally cheap to copy
  2. struct Value(u32);
  3. # [derive(Clone)] //you could derive Copy
  4. struct Id(u32);
  5. struct ValuesInfo {
  6. values: Vec<Value>,
  7. name: String,
  8. id: Id
  9. }
  10. struct ValueInfo{
  11. value: Value,
  12. name: String,
  13. id: Id
  14. }
  15. //No need to consume v. Not sure if it will come in handy
  16. fn extend_values(v: &Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
  17. //Use into_iter only if you need the ownership of the content of the array
  18. // which I don't think you need because you are cloning every value of ValueInfo
  19. //except for value which is already cheep to copy/clone
  20. v.iter().map(|values_info|{
  21. values_info.values.iter().map(|value|{
  22. ValueInfo{
  23. value: value.clone(),
  24. name: values_info.name.clone(),
  25. id: values_info.id.clone()
  26. }
  27. }).collect::<Vec<ValueInfo>>()
  28. }).collect::<Vec<Vec<ValueInfo>>>()
  29. }

也就是说,如果你真的不想复制/克隆Value,你需要事先输入clone name和id。编译器会阻止你使用values_info.name.clone(),因为函数into_iter已经使用了values_info。如果你真的不想复制Value,代码看起来应该是这样的

  1. # [derive(Clone)]
  2. struct Value(u32);
  3. # [derive(Clone)]
  4. struct Id(u32);
  5. struct ValuesInfo {
  6. values: Vec<Value>,
  7. name: String,
  8. id: Id
  9. }
  10. struct ValueInfo{
  11. value: Value,
  12. name: String,
  13. id: Id
  14. }
  15. fn extend_values(v: Vec<ValuesInfo>) -> Vec<Vec<ValueInfo>> {
  16. v.into_iter().map(|values_info|{
  17. let name = values_info.name.clone();
  18. let id = values_info.id.clone();
  19. values_info.values.into_iter().map(
  20. |value| {
  21. ValueInfo{
  22. value,
  23. name: name.clone(),
  24. id: id.clone(),
  25. }
  26. }).collect::<Vec<ValueInfo>>()
  27. }).collect::<Vec<Vec<ValueInfo>>>()
  28. }
展开查看全部

相关问题