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)
我做错了什么?
在第一个中,您从 "".to_string()
开始,这是一个拥有的 String
。 String
实现了 Add<&'_ str>
,它允许您使用 +
运算符连接其他借用的 &str
字符串。
把参数类型写出来,让你清楚地看到cur
和nxt
的区别:
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>
。
从 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)
我做错了什么?
在第一个中,您从 "".to_string()
开始,这是一个拥有的 String
。 String
实现了 Add<&'_ str>
,它允许您使用 +
运算符连接其他借用的 &str
字符串。
把参数类型写出来,让你清楚地看到cur
和nxt
的区别:
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>
。