我是一名经验丰富的开发人员,目前正在尝试自学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。
答案 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
必须返回Result
中and_then
包含的内容,而不必包含在{{1}中的情况。你的闭包没有返回任何东西,所以在Rust的视图中它实际返回map
,()
无法匹配()
。但是Result<U, E>
可以匹配()
,这就是第二个签名有效的原因。
答案 1 :(得分:2)
作为mdup explains,map
和and_then
用于转换带有闭包的Result
。当您想要更改内部类型时使用map
,当您想要链接导致另一个and_then
而没有嵌套它们的第二个事物时使用Result
。
但是, 这些都不适合你的情况,因为你不转换价值。相反,您需要match
或if 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());
};
}
}