2015-11-22 88 views
1

我是一位有經驗的開發人員,目前正試圖自學Rust,並正在編寫一個簡單的程序來讀取文件中的行。我已經閱讀了Rust std:io,std:result和其他文檔,這些代碼大部分都是直接從文檔中獲取的。我不明白爲什麼下面的程序不能編譯。E0308從讀取文件行中讀取行中的行。()

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 

我運行鏽1.4.0。

回答

2

作爲mdup explainsmapand_then用於變換一個Result與閉合。 map用於在想要更改內部類型時使用,當您想鏈接另一個導致另一個不嵌套它們的另一個Result時使用and_then

但是,你是不是轉化價值的這些既不是習慣了你的情況。相反,您需要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()); 
     };       
    }   
} 
+0

我將此標記爲答案,就好像mdup的答案很有幫助Shepmaster解釋了做這件事的最好方法是什麼,這對我很有幫助。 –

+0

好吧,剛剛發現約5分鐘的限制,所以上面的拼寫道歉,現在不能覈實它。我將在第4.7節「錯誤處理」中的文檔中將本來基於此代碼的代碼添加到檢查中[https://doc.rust-lang.org/stable/book/error-handling.html#the-limits-of-組合子。我現在看到他們爲什麼使用map,因爲他們實際上是鏈接在這個例子中的輸出。我確實有過使用比賽的第一次嘗試,但我的頭腦裏有錯誤,這確實有幫助。謝謝 –

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的的情況下,但它不必被包裹在map的情況下。你的關閉不會返回任何東西,所以在Rust看來,它實際上返回(),並且()不能匹配Result<U, E>。但()可匹配U,這就是第二個簽名起作用的原因。