E0308从reader.lines()

时间:2015-11-22 12:22:11

标签: io rust

我是一名经验丰富的开发人员,目前正在尝试自学Rust,我正在编写一个简单的程序来读取文件中的行。我已经阅读了Rust std:io,std:result和其他文档的正向和反向,这段代码主要是直接从文档中获取的。我无法理解为什么以下程序无法编译。

use std::io;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

fn main() {
    File::open("./data/test")
        .map_err(|err| err.to_string())
        .and_then( |mut dataFile| { 
             let mut reader = BufReader::new(dataFile);
             for line in reader.lines() {
                println!("{}",line.unwrap());

             };                           
        });        
}

我运行cargo build时收到的编译错误是

src/main.rs:10:35: 16:10 error: mismatched types:
 expected `core::result::Result<_, collections::string::String>`,
    found `()`
(expected enum `core::result::Result`,
    found ()) [E0308]
src/main.rs:10         .and_then( |mut dataFile| { 
src/main.rs:11              let mut reader = BufReader::new(dataFile);
src/main.rs:12              for line in reader.lines() {
src/main.rs:13                 println!("{}",line.unwrap());
src/main.rs:14    
src/main.rs:15              };                           
           ...
src/main.rs:10:35: 16:10 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error

我正在运行Rust 1.4.0。

2 个答案:

答案 0 :(得分:4)

您不应该使用and_then,而应使用map

正确的代码:

File::open("./data/test")
    .map_err(|err| err.to_string())
    .map(|mut dataFile| { 
         let mut reader = BufReader::new(dataFile);
         for line in reader.lines() {
            println!("{}",line.unwrap());
         };
    }); 

您可以在两个功能签名中看到它:

fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E>
fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E>

这里的关键区别在于操作op必须返回Resultand_then包含的内容,而不必包含在{{1}中的情况。你的闭包没有返回任何东西,所以在Rust的视图中它实际返回map()无法匹配()。但是Result<U, E>可以匹配(),这就是第二个签名有效的原因。

答案 1 :(得分:2)

作为mdup explainsmapand_then用于转换带有闭包的Result。当您想要更改内部类型时使用map,当您想要链接导致另一个and_then而没有嵌套它们的第二个事物时使用Result

但是, 这些都不适合你的情况,因为你转换价值。相反,您需要matchif let语句。这些更适合副作用

此外,Rust使用snake_case标识符,您不需要将任何变量标记为可变。这些都是编译后会看到的编译器警告。

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

fn main() {
    let f = File::open("./data/test")
        .map_err(|err| err.to_string());

    if let Ok(data_file) = f {
        let reader = BufReader::new(data_file);
        for line in reader.lines() {
            println!("{}", line.unwrap());
        };                           
    }        
}