cloned()
需要将&&str
项目转换为&str
项目,不会进行任何分配。当rust@1.36
获得稳定版本后,最终可以用copied()
替换。use itertools::Itertools; // 0.8.0
fn main() {
let words = ["alpha", "beta", "gamma"];
let merged: String = words.iter().cloned().intersperse(", ").collect();
assert_eq!(merged, "alpha, beta, gamma");
}
您可以通过使用迭代器的fold
函数轻松实现:
let s = it.fold(String::new(), |a, b| a + b + "\n");
完整代码如下:
fn main() {
let xs = vec!["first", "second", "third"];
let it = xs.into_iter();
// let s = it.collect::<Vec<&str>>().join("\n");
let s = it.fold(String::new(), |a, b| a + b + "\n");
let s = s.trim_end();
println!("{:?}", s);
}
编辑:在Sebastian Redl的评论后我检查了折叠使用的性能成本并在playground上创建了基准测试。
你可以看到对于许多迭代方法,fold
的使用需要更长时间。
虽然没有检查分配的内存使用情况。
black_box(xs).iter().copied()
在 collect+join 上的执行时间现在是 fold 的两倍(black_box(xs)
不重要,xs
是相同的)。<3 微基准测试。 - chpiovec!["hey"; 100_000].into_iter().collect<Vec<_>>
这样的东西优化为直接返回原始的 vec?! - chpiolet mut it = xs.into_iter(); let first = it.next().unwrap_or("").to_owned(); let r = it.fold(first, |a, b| a + "\n" + b);
,这样你最终得到的是一个 String
而不是 &str
。 - d2weberitertools
,你不仅可以使用intersperse()
还可以使用join()
:use itertools::Itertools;
let s = it.join("\n");
它比 intersperse()
更通用(它接受任何实现了 Display
接口的类型),但因此可能会更慢(尽管我没有进行基准测试)。
fn main() {
let it = ["1", "2", "3"].into_iter();
let res = it.map(String::from).reduce(|acc, s| format!("{acc}, {s}")).unwrap_or_default();
assert_eq!(&res, "1, 2, 3");
}
Cow
来避免不必要的分配。use std::borrow::Cow;
fn main() {
let it = ["1", "2", "3"].into_iter();
let res = it.map(Cow::from).reduce(|mut acc, s| {
acc.to_mut().push('\n');
acc.to_mut().push_str(&s);
acc
}).unwrap_or_default();
assert_eq!(&res, "1\n2\n3");
}
在 Rust 文档中有相关的示例:这里。
let words = ["alpha", "beta", "gamma"];
// chars() returns an iterator
let merged: String = words.iter()
.flat_map(|s| s.chars())
.collect();
assert_eq!(merged, "alphabetagamma");
你也可以使用 Extend
trait:
fn f<'a, I: Iterator<Item=&'a str>>(data: I) -> String {
let mut ret = String::new();
ret.extend(data);
ret
}
flat_map
的情况下运作,因为 String 已经实现了 Extend<&str>
。 - chpio
itertools
更快,因为SliceConcatExt :: join
可以提前计算出完整字符串所需的大小,因此在累加过程中绝对不需要重新分配;而其他方法可能需要重新分配字符串。您一定要进行基准测试。 - Sebastian Redl