【发布时间】:2021-01-21 11:43:31
【问题描述】:
正如标题所说,我有一个Strings 中的Iterator 并想生成一个Vec<char>,只需将它们全部连接起来(同时将每个String 视为一系列Unicode 标量值,正如.chars() 所做的那样)。 (我不需要在Strings 或类似的东西之间插入字符串,尽管我知道使用itertools::intersperse 不会更难,如other answers 所述。)
pub fn flatten_strings(ss: impl Iterator<Item=String>) -> Vec<char> {
// ???
}
(如果我可以实现稍微更通用的类型签名,那就太好了,但不是特别必要:)
pub fn flatten_strings<S>(ss: impl Iterator<Item=String>) -> S where S: FromIterator<char> {
// ???
}
无论如何,这是一个简单的尝试:
pub fn flatten_strings(ss: impl Iterator<Item=String>) -> Vec<char> {
ss.flat_map(|s| s.chars()).collect()
}
不幸的是,这不起作用,因为chars 返回Chars,其中包含对它所基于的String 的引用;但是 lambda 获得了 String 的所有权,并在它返回时将其丢弃。
error[E0515]: cannot return value referencing function parameter `s`
--> src/main.rs:2:21
|
2 | ss.flat_map(|s| s.chars()).collect()
| -^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `s` is borrowed here
我可以通过将所有Strings 收集到一个中间向量中来解决这个问题,这样我就可以让某人拥有所有Strings,并且我正在平面映射&Strings 的迭代器而不是Strings ;但是必须分配 Strings 的中间向量似乎效率低下,并且在某种程度上破坏了使用 Rust 的漂亮迭代器抽象的意义:
pub fn flatten_strings(ss: impl Iterator<Item=String>) -> Vec<char> {
ss.collect::<Vec<String>>().iter().flat_map(|s| s.chars()).collect()
}
同样,我可以手动滚动一个循环,但这看起来也很难看。我可以在不进行额外分配且不离开 Rust 的迭代器抽象的情况下高效地实现此功能吗?
【问题讨论】:
-
你不能实现
flatten_strings(ss: impl Iterator<Item = &str>) -> impl Iterator<Item = chars> + '_吗? -
在我的用例中,输入迭代器中的
Strings 也是中间值(例如,由mapping 与format!不同的迭代器产生);我试图不分配空间来一次容纳所有这些。 -
以上链接能回答您的问题吗?
标签: rust