2016-03-19 4 views
3

io::stdioインスタンスを入力し、BufReaderというファイルをラップしてバッファリングされた入力ソースを想定してコードを書き込もうとしています。私が試してみましたio :: stdioとBufReaderの間のBufRead特性の互換性を強制する

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

もの:ここでは、コードだ

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()); 

:私はBufRead型にio::stdio()をキャストしようとしているのいくつかのバリエーションを試したし、すべてがの一の以上のバリエーションで失敗してきました:私も、独自の機能と戻り値の型シグネチャにそのコードを抽出しようとした

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. 

同様のエラー条件で失敗します。どのようにしてBufferedReaderstdioに、またはBufferedReaderFileにして、どこのタイプのエラーも発生させない「リーダー」変数を作成できますか?

+0

以下の回答の要約:「ボックス」タイプを使用してください。 Boxはソフト多形参照です(C/C++スタイルの言語のポインタに似ています)。 –

答えて

1

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を避けることができます。

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 stdin = io::stdin(); 
let mut reader = Box::new(stdin.lock()) as Box<BufRead>; 

//... 

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

興味深い 'BufRead'メソッドはすべて'&mut self'を取るので、 '&BufRead'はあまり役に立ちません。 – fjh

+0

条件の前に変数を宣言する必要はありません。条件に使用されていないからです。したがって、ここでは本当に不要な特性オブジェクトを避けるためにコードを書き直す方がよいでしょう。 –

+0

回答が更新されました。 – aSpex