fold 对它接受的闭包很挑剔

fold is picky about closures it accepts

(这里是 rust noob;我试图了解在高阶函数情况下 can/cannot/should/shouldn 不能通过引用传递的内容)

let a = [1, 2, 3];

此调用有效:

let sum = a.iter().fold(0, |acc:  i32, x: &i32| acc + x);

这些不:

let sum = a.iter().fold(0, |acc: i32, x: i32| acc + x);
let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);

错误信息是

error[E0631]: type mismatch in closure arguments
 --> main.rs:8:22
  |
8 |   let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
  |                      ^^^^    --------------------------- found signature of `for<'r> fn(&'r i32, i32) -> _`
  |                      |
  |                      expected signature of `fn({integer}, &{integer}) -> _`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0631`.

该解释没有提供任何有趣的内容。它表示闭包的参数与 fold 的参数不匹配。但是,我看不出它是如何从 fold:

的声明中得出的
fn fold<B, F>(self, init: B, f: F) -> B
where
    F: FnMut(B, Self::Item) -> B

为什么第二个参数应该是 &{integer},而第一个参数应该是 {integer}

迭代器中的项是从数组中借用的,所以&i32不是i32。这种形式有效是因为累加器是自己的,而物品是借来的:

let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);

您可以转换迭代器,使其项被复制而不是被引用,然后第一种形式将起作用:

let sum = a.iter().copied().fold(0, |acc: i32, x: i32| acc + x);

第三种形式永远行不通。闭包需要能够 return 一个新值来更新累加器。累加器的类型是i32。它不能是引用,因为你不能 return 来自闭包的引用(原始值将被删除,Rust 不会让你 return 悬空指针)。

查看fold()

的声明
fn fold<B, F>(self, init: B, f: F) -> B
where
    F: FnMut(B, Self::Item) -> B

你可以看到函数有两个泛型类型参数——累加器的类型B和闭包的类型F。闭包类型具有 trait bound FnMut(B, Self::Item) -> B,这意味着第一个参数的类型与累加器的类型相同,而第二个参数的类型是迭代器的项类型。

在调用中

let sum = a.iter().fold(0, |acc, x| acc + x);

我们使用项目类型为 &i32 的迭代器,并且您的累加器被初始化为 0,因此它的类型被推断为 i32(这是默认的整数类型在没有任何进一步资格的情况下)。