如何 flat_map 并从字符串的迭代器中拆分

How to flat_map and split from an iterator of Strings

有没有办法在不切换到使用 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 时,我得到了一个引用迭代器并且一切正常,但我想知道是否可以在 [=17] 的迭代器上进行这项工作=]s.

您的代码的问题在于您正在执行这些操作:

  1. 您正在使用 into_iter
  2. 使用您的向量
  3. 因此,在闭包内部,您通过 split
  4. 借用了 String 的值
  5. 在您的临时迭代器中,您持有对此字符串的引用

结论:您正在尝试 return 对局部变量的引用。

要解决此问题,您必须从拆分字符串创建拥有的字符串,并收集它们以不再保留引用:

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<_>>());
}

我遇到了同样的问题,最终创建了一个迭代器来获取字符串的所有权,这是代码。由于您按 space 拆分,它应该适合

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)
}