使用std :: iter :: Iterator map

时间:2015-06-02 23:20:28

标签: file text io rust

我试图在Rust中读取和解析文本文件。每一行都是有符号整数。我可以使用for line in lines次迭代来完成此操作,但我无法使用iter().map(|l| ...)一行进行此操作。我得到了

expected `&core::result::Result<collections::string::String, std::io::error::Error>`,
found `core::result::Result<_, _>`

当我尝试模式匹配Ok(s) => match s.parse()时,但我无法深入了解我做错了什么。整个例子如下。底部的代码是产生错误的代码。

谁能说出我做错了什么?

use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

fn main() {
    // Create a path to the desired file
    let path = Path::new("input/numbers.txt");
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    // Collect all lines into a vector
    let reader = BufReader::new(file);
    let lines: Vec<_> = reader.lines().collect();

    // Works.
    let mut nums = vec![];       
    for l in lines {
        println!("{:?}", l);
        let num = match l {
            Ok(s) => match s.parse() { 
                Ok(i) => i,
                Err(_) => 0
            },
            Err(_) => 0
        };
        nums.push(num);
    }

    // Doesn't work!       
    let nums: Vec<i64> = lines.iter().map(|l| match l {
        Ok(s) => match s.parse() {
            Ok(i) => i,
            Err(_) => 0
        },
        Err(_) => 0
    });
}

1 个答案:

答案 0 :(得分:8)

让我们看看完整的错误消息,它指出了我们的错误:

Result

编译器期待Ok(s),但找到l,问题在于Result模式。 &的类型是fn main() { let lines: Vec<Result<_, ()>> = vec![Ok("1"), Ok("3"), Ok("5")]; // HERE V let nums: Vec<i64> = lines.iter().map(|&l| match l { Ok(s) => match s.parse() { Ok(i) => i, Err(_) => 0 }, Err(_) => 0 }).collect(); println!("{:?}", nums) } 引用,因为您使用的是ave() - 它会将iter返回到向量中的项目。< / p>

最短的解决方法是为闭包变量的模式匹配添加Vec

// HERE                    V~~~~
let nums: Vec<i64> = lines.into_iter().map(|l| match l {

我还必须添加an iterator of references才能返回let nums: Vec<i64> = lines.into_iter().map(|l| { l.ok().and_then(|s| s.parse().ok()).unwrap_or(0) }).collect();

您可以进行的另一项更改是使用collect 使用输入向量,然后迭代向量中的每个值:

{{1}}

为了更好地衡量,您可以使用into_iterokand_then更简洁地说出相同的内容:

{{1}}