Fold 对它接受的闭包很挑剔

n. *_* m. 2 reference fold rust

(这里是生锈菜鸟;我试图了解在高阶函数情况下可以/不能/应该/不应该通过引用传递什么)

let a = [1, 2, 3];
Run Code Online (Sandbox Code Playgroud)

此调用有效:

let sum = a.iter().fold(0, |acc:  i32, x: &i32| acc + x);
Run Code Online (Sandbox Code Playgroud)

这些不:

let sum = a.iter().fold(0, |acc: i32, x: i32| acc + x);
let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
Run Code Online (Sandbox Code Playgroud)

错误信息是

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`.
Run Code Online (Sandbox Code Playgroud)

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

fn fold<B, F>(self, init: B, f: F) -> B
where
    F: FnMut(B, Self::Item) -> B
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*all 5

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

let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);
Run Code Online (Sandbox Code Playgroud)

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

let sum = a.iter().copied().fold(0, |acc: i32, x: i32| acc + x);
Run Code Online (Sandbox Code Playgroud)

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

  • 您可以从闭包返回引用,尽管它们的生命周期需要超过闭包。示例 ` fn main(){ let a = [1,2,3]; 令互和 = 0;let res = a.iter().copied().fold(&amp;mut sum, |acc:&amp;mut i32, x: i32| -&gt; &amp;mut i32 {*acc += x;acc}); println!("{}", res); ` &lt;https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=898d3a974f32a4aa6d2bc435148f41b2&gt; (2认同)