如何从Strings的迭代器中进行flat_map和拆分



有没有一种方法可以在不切换到使用iter而不是into_iter的情况下实现这一点?

let strings: Vec<String> = vec!["1 2".to_string(), "3 4".to_string()];
strings.into_iter().flat_map(|str| str.split(" "));

问题是

error[E0515]: cannot return value referencing function parameter `str`
--> src/lib.rs:3:40
|
3 |     strings.into_iter().flat_map(|str| str.split(" "));
|                                        ---^^^^^^^^^^^
|                                        |
|                                        returns a value referencing data owned by the current function
|                                        `str` is borrowed here

当使用iter而不是into_iter时,我得到了一个引用的迭代器,一切都正常,但我想知道是否可以在Strings的迭代机上实现。

代码的问题在于您正在执行以下操作:

  1. 您正在使用into_iter消耗矢量
  2. 因此,在闭包中,您通过使用split借用的值来获取String
  3. 在临时迭代器中,您持有对以下字符串的引用

结论:您正试图返回对局部变量的引用。

为了解决这个问题,您必须从拆分的字符串中创建所拥有的字符串,并收集它们以不再包含引用:

fn main() {
let strings = vec!["1 2".to_string(), "3 4".into()];
let result = strings.into_iter().flat_map(|str| str.split(" ").map(str::to_owned).collect::<Vec<_>>());
println!("{:?}", result.collect::<Vec<_>>());
}

事实上,如果一开始不消耗矢量,成本会更低:

fn main() {
let strings = vec!["1 2".to_string(), "3 4".into()];
let result = strings.iter().flat_map(|str| str.split(" ")).map(str::to_owned);
println!("{:?}", result.collect::<Vec<_>>());
}

我遇到了同样的问题,最终创建了一个迭代器来获得字符串的所有权,下面是代码。既然你是按空间划分的,它应该适合

struct Words {
buf: String,
offset: usize,
}
impl Words {
fn new(buf: String) -> Words {
Words { buf, offset: 0 }
}
}
impl Iterator for Words {
type Item = String;
fn next(&mut self) -> Option<String> {
let s = &(self.buf)[self.offset..];
let left = s.chars().take_while(|x| x.is_whitespace()).count();
let right = left + s[left..].chars().take_while(|x| !x.is_whitespace()).count();
if left < right {
self.offset += right;
return Some(String::from(&s[left..right]));
}
None
}
}

以下是我如何使用

fn read_file<'a>(buf: impl BufRead) -> impl Iterator<Item = String> {
buf.lines().filter_map(Result::ok).flat_map(Words::new)
}

最新更新