克隆特性 BufRead 的行时类型不匹配

Type mismatch when cloning the lines of the trait BufRead

为了更好地使用 Rust,我决定实现一个简单的词法分析器来逐行分析一些文档。

因为我必须在特征 BufRead 的行上至少迭代两次,所以我正在克隆 BufRead 的行,但出现以下错误:

error[E0271]: type mismatch resolving `<std::io::Lines<T> as std::iter::Iterator>::Item == &_`
  --> <anon>:18:23
   |
18 |     let lines = lines.cloned();
   |                       ^^^^^^ expected enum `std::result::Result`, found reference
   |
   = note: expected type `std::result::Result<std::string::String, std::io::Error>`
   = note:    found type `&_

error[E0271]: type mismatch resolving `<std::io::Lines<T> as std::iter::Iterator>::Item == &_`

我明白错误是什么,但是基于 following code,我如何告诉编译器 IteratorItem 应该是什么,以便它可以正确地转换类型?

use std::fmt::Write;
use std::io::{BufRead, BufReader, Lines, Read};

pub struct DocumentMetadata {
    language: String,
    // ...
}

pub fn analyze<T: BufRead>(document: T) -> Result<DocumentMetadata, ()> {
    let lines = document.lines();
    let language = guess_language(&lines);

    // Do more lexical analysis based on document language

    Ok(DocumentMetadata {
        language: language,
        // ...
    })
}

fn guess_language<T: BufRead>(lines: &Lines<T>) -> String {
    let lines = lines.cloned();
    for line in lines {
        let line = line.unwrap();
        // Try to guess language
    }
    "en".to_string()
}

#[test]
fn it_guesses_document_language() {
    let mut document = String::new();
    writeln!(&mut document, "# language: en").unwrap();
    let document = BufReader::new(document.as_str().as_bytes());

    match analyze(document) {
        Ok(metadata) => assert_eq!("en".to_string(), metadata.language),
        Err(_) => panic!(),
    }
}

出于单元测试的目的,我正在构建一个带有 String 的缓冲区,但在正常使用中我从 File.

中读取它

查看 Iterator::cloned 定义:

fn cloned<'a, T>(self) -> Cloned<Self> 
    where Self: Iterator<Item=&'a T>, 
          T: 'a + Clone

以及 io::LinesIterator 的实施:

impl<B: BufRead> Iterator for Lines<B> {
    type Item = Result<String>;
}

您不能使用 cloned,因为迭代器项不是引用。否则你不能 "tell" 编译器;这不是类型的工作方式。

As I have to iterate at least two times over the lines of the trait BufRead, I am cloning the lines of my BufRead

这真的没有意义。克隆 reader 的行不会保存任何内容。事实上,它可能只会让事情 变得更糟 。您将创建一次字符串,除了克隆它们之外不使用它们,然后在您再次迭代时第三次创建它们。

如果您希望避免重新创建所有字符串,collect 将所有字符串放入 Vec 或其他集合中,然后迭代多次:

pub fn analyze<T: BufRead>(document: T) -> Result<DocumentMetadata, ()> {
    let lines: Result<Vec<_>, _> = document.lines().collect();
    let lines = lines.unwrap();
    let language = guess_language(&lines);

    // Do more lexical analysis based on document language

    Ok(DocumentMetadata {
        language: language,
        // ...
    })
}

fn guess_language<'a, I>(lines: I) -> String 
    where I: IntoIterator<Item = &'a String>,
{
    for line in lines {
        // Try to guess language
    }
    "en".to_string()
}