2016-03-19 50 views
3

我想輸入一個io::stdio實例和一個BufReader包裝文件,以便我可以編寫假設緩衝輸入源的代碼。我試過的嘗試投放的io::stdio()BufRead類型的若干變化和所有已經失敗的一個或多個變化:在io :: stdio和BufReader之間強制BufRead特性兼容性

error: mismatched types: 
expected `std::io::stdio::StdinLock<'_>`, 
    found `std::io::buffered::BufReader<std::fs::File>` 
(expected struct `std::io::stdio::StdinLock`, 
    found struct `std::io::buffered::BufReader`) [E0308] 
csv_to_json.rs:26  reader = BufReader::new(file.unwrap()); 

下面的代碼:我已經試過

use std::io; 
use std::io::BufReader; 
use std::io::prelude::*; 
use std::env; 
use std::process::exit; 
use std::fs::File; 

fn usage() { 
    println!("Usage: cat input.csv | csv_to_json"); 
} 

fn main() { 
    let stdin = io::stdin(); 
    let mut reader = stdin.lock(); // Assignment. (1) 
    let args: Vec<String> = env::args().collect(); 

    if args.len() > 1 { 
     usage(); 
     exit(1); 
    } else if args.len() == 1 { 
     let file = File::open(args[0].clone()); 
     if !file.is_ok() { 
      usage(); 
      exit(1); 
     } 
     reader = BufReader::new(file.unwrap()); // Reassignment. This is the line that fails. 
    } 

    // Rest of the code works with reader assuming a buffered input source. 
} 

事:

let mut reader : BufRead = io::stdin(); // Fails. 
let mut reader : BufReader<Read> = io::stdin(); // Fails. 
let mut reader : BufReader<_> = io::stdin(); // Fails 
let mut reader : BufRead = io::stdin().lock(); // Fails later. 
let mut reader = BufReader::new(io::stdin()); // Fails with type mismatch. 
let mut reader = BufReader::new(io::stdin().lock()); // Fails with type mismatch. 

我甚至試着將代碼解壓到自己的函數中,返回類型簽名失敗,出現類似的錯誤情況。如何在File上創建一個「閱​​讀器」變量,該變量或者是BufferedReader而不是stdioBufferedReader而不是面向所有類型的錯誤?

+0

答案如下:使用「箱子」類型。 Box是一個軟多態的引用(類似於C/C++風格語言中的指針)。 –

回答

1

這將工作。

use std::io; 
use std::io::BufReader; 
use std::io::prelude::*; 
use std::env; 
use std::process::exit; 
use std::fs::File; 

fn usage() { 
    println!("Usage: cat input.csv | csv_to_json"); 
} 

fn main() { 
    let stdin = io::stdin(); 
    let mut reader = Box::new(stdin.lock()) as Box<BufRead>; 
    let args: Vec<String> = env::args().collect(); 

    if args.len() > 1 { 
     usage(); 
     exit(1); 
    } else if args.len() == 1 { 
     let file = File::open(args[0].clone()); 
     if !file.is_ok() { 
      usage(); 
      exit(1); 
     } 
     reader = Box::new(BufReader::new(file.unwrap())); 
    } 
} 
+0

感謝您指出在這種情況下正確使用Box。很有幫助。 –

4

您的代碼可以重寫,因此無需重新指定reader變量(請參閱@Vladimir Matveev answer)。

如果你真的需要它,然後reader變量必須是trait object

let mut bufread;//must be defined before reader to avoid lifetime issues 
let stdin = io::stdin(); 
let mut reader = &mut stdin.lock() as &mut BufRead; // Assignment. (1) 

//... 

bufread = BufReader::new(file.unwrap());//store BufReader value 
reader = &mut bufread;// reassign BufRead reference 

特質對象的盒裝形式允許以避免額外變量bufread

let stdin = io::stdin(); 
let mut reader = Box::new(stdin.lock()) as Box<BufRead>; 

//... 

reader = Box::new(BufReader::new(file.unwrap())); 
+1

'&BufRead'不會很有幫助,因爲所有有趣的'BufRead'方法都需要'&mut self'。 – fjh

+0

我想說明的是,沒有必要在條件之前聲明任何變量,因爲它們沒有用於它。所以最好重寫代碼以避免trait對象,因爲在這裏它們確實是不必要的。 –

+0

答覆已更新。 – aSpex