Rust 中字符串连接的 Reduce vs Fold

Reduce vs Fold for String Concatenation in Rust

从 1.51 开始,Rust 包含了 reduce,我从 Scala 就习惯了。 fold 与 Scala 中的 foldLeft 类似,但 reduce 不同。我哪里错了?

效果很好:

let ss = vec!["a", "b", "c"].iter()
.fold("".to_string(), |cur, nxt| cur + nxt);

println!("{}", ss);

这不是:

let ss = vec!["a", "b", "c"].iter()
.reduce(|cur, nxt| cur + nxt);

println!("{}", ss);

错误:

error[E0369]: cannot add `&&str` to `&&str`
 --> src/main.rs:3:28
  |
3 |     .reduce(|cur, nxt| cur + nxt);
  |                        --- ^ --- &&str
  |                        |
  |                        &&str

error[E0277]: `Option<&&str>` doesn't implement `std::fmt::Display`
 --> src/main.rs:5:20
  |
5 |     println!("{}", ss);
  |                    ^^ `Option<&&str>` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Option<&&str>`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = note: required by `std::fmt::Display::fmt`
  = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

(Playground)

我做错了什么?

在第一个中,您从 "".to_string() 开始,这是一个拥有的 StringString 实现了 Add<&'_ str>,它允许您使用 + 运算符连接其他借用的 &str 字符串。

把参数类型写出来,让你清楚地看到curnxt的区别:

let ss = vec!["a", "b", "c"].iter()
    .fold("".to_string(), |cur: String, nxt: &&str| cur + nxt);

另一方面,reduce() 调用仅适用于 &str,但 &str 不支持与 + 的串联。没有 Add impl.

let ss = vec!["a", "b", "c"].iter()
    .reduce(|cur: &str, nxt: &str| cur + nxt); // &str + &str not defined

虽然 &str 不支持串联,但 String 支持,因为它可以高效地做到这一点。 a + b 消耗 a,为结果 String 重新使用其缓冲区。它不必分配 O(a.len()) space 也不必花费 O(a.len()) 时间复制 a 的现有内容。 b 只是就地附加到 a 的缓冲区。

因此,如果您将借用的 &str 转换为拥有的 String,它会编译:

let ss = vec!["a", "b", "c"].iter()
    .map(|s| s.to_string())
    .reduce(|cur: String, nxt: String| cur + &nxt)
    .unwrap();

还请注意 reduce() returns 需要解包的 Option<String>