【问题标题】:How to fold vector of vector in rust?如何在锈中折叠矢量的矢量?
【发布时间】:2022-01-21 18:09:53
【问题描述】:

我有一个向量,如下所示。

    let m: Vec<Vec<u64>> = vec![
        vec![1, 2, 3, 4, 5],
        vec![1, 2, 3, 4, 5],
        vec![1, 2, 3, 4, 5],
        vec![1, 2, 3, 4, 5],
        vec![1, 2, 3, 4, 5]
    ];

add 函数旨在将两个向量的每个元素相加。

fn add(xs: &Vec<u64>, ys: &Vec<u64>) -> Vec<u64> {
    xs.iter().zip(ys.iter()).map(|(x, y)| x + y).collect()
}

现在,我想fold 向量m 的向量。

我尝试的是:

    let s: Vec<u64> = m[1..]
        .iter()
        .fold(m[0], |acc, xs| add(&acc, xs));

但是这段代码没有通过编译器。

   |
16 |         .fold(m[0], |acc, xs| add(&acc, xs));
   |               ^^^^ move occurs because value has type `Vec<u64>`, which does not implement the `Copy` trait

我尝试添加 &amp; 但编译器仍然拒绝:

   |
16 |         .fold(&m[0], |acc, xs| add(&acc, xs));
   |               ^^^^^ expected struct `Vec`, found `&Vec<u64>`
   |
   = note: expected struct `Vec<u64>`
           found reference `&Vec<u64>`
help: consider removing the borrow
   |
16 -         .fold(&m[0], |acc, xs| add(&acc, xs));
16 +         .fold(m[0], |acc, xs| add(&acc, xs));
   |

我认为add 函数的签名是正确的,因为它不想获取参数向量的所有权,并且它返回一个新向量,因此应将所有权传递给调用者。

实际上,我尝试了所有可能的组合(从函数中添加/删除&amp; 等),但无法使代码通过编译器。

你能告诉我我错过了什么,上面的代码有什么问题吗?谢谢。

【问题讨论】:

  • fold 的第一个参数必须与其输出的类型相同。因此传递&amp; m[0](类型为&amp; Vec&lt;u64&gt;)是行不通的,因为您希望折叠返回Vec&lt;u64&gt;。一种选择是以m[0].clone() 作为初始值。显然,这确实涉及克隆,但无论如何您都需要以某种方式分配输出。

标签: rust fold


【解决方案1】:

fold 的第一个参数必须与其输出的类型相同。因此,您建议通过 &amp; m[0](其类型为 &amp; Vec&lt;u64&gt;)的建议将不起作用,因为您希望折叠返回 Vec&lt;u64&gt;(通知值与借用值)。并且使用m[0](不借用)将不起作用,因为您将尝试从稍后使用的向量(在迭代本身中)移动。

一个选项可能是以m[0].clone() 作为初始值。显然,这确实涉及克隆,但是无论如何您都需要以某种方式分配输出,因此无法做得更好。这有效:

let s: Vec<u64> = m[1..].iter().fold(m[0].clone(), |acc, xs| add(& acc, xs));

不相关:我建议您将add 更改为具有更通用的签名fn add(xs: &amp; [u64], ys: &amp; [u64]) -&gt; Vec&lt;u64&gt;。你仍然可以按原来的方式使用它(因为&amp; Vec&lt;u64&gt; 强制转换为&amp; [u64]),但它更通用,因为其他类型也强制转换为&amp; [u64]

【讨论】:

  • 您提到添加clone() 是一种选择。请您解释一下其他可能的选择吗?
  • @ntalbs:好问题!实际上,我没有看到任何更好的选择。结果向量需要在某个时候分配。在我看来,唯一合理的选择是将初始值设置为一个零向量,然后折叠所有m,但这并不比仅使用m[0] 的克隆进行初始化更好。
猜你喜欢
  • 1970-01-01
  • 2016-04-10
  • 1970-01-01
  • 2012-05-16
  • 1970-01-01
  • 2023-01-12
  • 2017-06-18
  • 2013-11-02
  • 2020-06-05
相关资源
最近更新 更多