如何通过 Rust 的约简得到向量的乘积?

Pet*_* Zo 2 rust

我知道如何使用fold来获取产品:

let product = V.iter().fold(1, |res, a| res * a);
Run Code Online (Sandbox Code Playgroud)

但我不知道如何获得该产品reduce。我知道我可以使用以下方法into_iter

let produce = V.into_iter().reduce(|a, b| a * b).unwrap();
Run Code Online (Sandbox Code Playgroud)

into_iter会感动主人。如果我只使用iter方法,它会引发错误......

 $ rustc main.rs
error[E0308]: mismatched types
 --> main.rs:3:42
  |
3 |     let produce = V.iter().reduce(|a, b| a * b).unwrap();
  |                                          ^^^^^
  |                                          |
  |                                          expected `&{integer}`, found integer
  |                                          help: consider borrowing here: `&(a * b)`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
p
Run Code Online (Sandbox Code Playgroud)

但是当我只获取它的引用时,rustc 告诉我我无法获取临时值的引用。

请告诉我如何通过 获得答案reduce或者为什么我无法通过 获得答案reduce

use*_*342 8

正如另一个答案中所述,正确的解决方案是复制这些值,即使用适配器(例如Iterator::copied(). 但根本问题值得更详细地讨论。

V.iter()被限制在迭代完成后保持向量完整,因此它在生成元素时无法从向量中移动元素。并且Vec::iter()必须适用于所有类型的值,而不仅仅是数字,因此它不能复制元素,甚至不能克隆它们,因为它们可能不是Copyor Clone。相反,Vec::iter()生成对存储在向量中的元素的引用,让根据需要复制或克隆它们(或者只是检查它们而不执行任何操作)。因此,在您的情况下V.iter()会产生 诸如 之类的引用&u32

结果是:

  • fold()之所以有效,是因为它使用初始值 ( ) 的类型u32作为累加器类型。在闭包中,|res, a| res * a提供/期望的类型reduce|res: u32, a: &u32| -> u32 { res * a }。由于u32 * &u32给你一个u32,闭包体满足它的签名。

  • reduce()不起作用,因为它将项目类型 ( &u32) 作为累加器的类型。|a, b| a * bis的完整签名|a: &u32, b: &u32| -> &u32 { a * b },它无法编译,因为&u32 * &u32在闭包主体中不生成 a&u32而是生成 a u32

请注意,您无法reduce()通过将闭包编写为 来修复变体|a, b| &(a * b),即使编译器只是建议这样做。虽然这在类型系统级别上是正确的,但它会被借用检查器拒绝。由于 Rust 没有垃圾收集器,因此每个引用都必须指向一个比它寿命长的拥有的对象,并且没有地方可以存储a * b. 返回对保存结果的临时值的引用将导致悬空引用,如果您尝试这样做,编译器会及时指出这一点。(但只是为了好玩,您可以编写V.iter().reduce(|a, b| Box::leak(Box::new(a * b))),它将通过类型和借用检查器,但代价是堆分配和泄漏每个处理的数字。)

正确的答案通过将所有类型更改为 来解决问题u32,因此传递给的闭包reduce()变为|a: u32, b: u32| -> u32 { a * b },这当然可以编译。