使用std::iter::Iterator映射将文本文件行解析为数字



我正在尝试阅读和解析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
    });
}

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

<anon>:5:9: 5:14 error: mismatched types:
 expected `&core::result::Result<&str, ()>`,
    found `core::result::Result<_, _>`
(expected &-ptr,
    found enum `core::result::Result`) [E0308]
<anon>:5         Ok(s) => match s.parse() {
                 ^~~~~

编译器期望&Result,但发现Result,问题是Ok(s)模式。l的类型是对Result引用,因为您使用的是iter——它返回指向vector中元素的引用迭代器。

最短的修复方法是在闭包变量的模式匹配中添加一个&:

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

我还必须添加collect以返回Vec

你可以做的另一个改变是使用into_iter消耗输入向量,然后迭代向量中的每个值:

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

为了更好地衡量,您可以使用ok, and_thenunwrap_or来更简洁地表达相同的内容:

let nums: Vec<i64> = lines.into_iter().map(|l| {
    l.ok().and_then(|s| s.parse().ok()).unwrap_or(0)
}).collect();

相关内容

  • 没有找到相关文章

最新更新