2016-05-04 16 views
3

テキストを解析する関数を書いていますが、テキストは外部ファイルまたは内部の&strから来る可能性があります。 parse機能のように行くことがあります。std :: str :: linesとstd :: io :: linesをどのように組み合わせるか?

fn parse(lines: GenericLinesGenerator) { 
    for line in lines { 
     // parse content 
    } 
} 

...そして、それは次のように呼び出すことができます。

use std::io::BufReader; 
use std::fs::File; 
let fin = BufReader::new(File::open("info.txt").expect("not found")); 
parse(TransformFromIO(fin.lines())) 

または

let content: &'static str = "some\nlong\ntext"; 
parse(TransformFromStr(content.lines())) 

は、このようなparse機能を実現することが可能です?

impl<B: BufRead> Iterator for io::Lines<B> { 
    type Item = Result<String>; 
} 
impl<'a> Iterator for str::Lines<'a> { 
    type Item = &'a str; 
} 

あなたが何らかの形でその違いを処理する必要があります。

答えて

4

2回の反復子が同じ値を生成しません。最も重要な違いは、io::Linesが失敗することです。です。あなたのプログラムはそれに対処する方法を決めなければなりません。私はプログラムを中止することを選択しました。

次に、イテレータに変換できるすべての型を受け入れ、イテレータから返された値を扱うことができる型に変換する必要があります。共通の分母は&strであるようです。

これはIntoIteratorBorrowを使用することにより解決される:形質バウンドの詳細についてはwhere clauses

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

fn parse<I>(lines: I) 
    where I: IntoIterator, 
      I::Item: Borrow<str>, 
{ 
    for line in lines { 
     println!("line: {}", line.borrow()); 
    } 
} 

fn main() { 
    parse("alpha\nbeta\ngamma".lines()); 

    println!("----"); 

    let f = File::open("/etc/hosts").expect("Couldn't open"); 
    let b = BufReader::new(f); 
    parse(b.lines().map(|l| l.expect("Bad line!"))); 
} 

チェックThe Rust Programming Languageセクション。 parse機能にバインドさBorrowを使用して

+0

驚くばかり!ありがとう! – knight42

+0

この種の問題に対して新しい特性を実装する必要はありません。 – WiSaGaN

2

あなたが&strを借りることができますが、あなたはString値が必要な場合は、より良いアプローチはCowを使用することです。 parseがファイルからのラインと呼ばれても

常に割り当てるString値を得るためにline.borrow().to_string()を使用して、(この場合、lines.mapStringを生成します)。

&strからラインと呼ばれる場合割り当てるline.into_owned()を使用して、ファイルからの線で呼び出されたときに(ちょうどCow::Ownedに渡さString値をアンラップします)割り当てないであろう。

use std::borrow::Cow; 
use std::io::{BufReader, BufRead}; 
use std::iter::IntoIterator; 
use std::fs::File; 

fn parse<'a, I>(lines: I) 
    where I: IntoIterator, 
      I::Item: Into<Cow<'a, str>> 
{ 
    for line in lines { 
     let line: Cow<'a, str> = line.into(); 
     let line: String = line.into_owned(); 
     // or 
     let line = line.into().into_owned() 
     println!("{}", line); 
    } 
} 

fn main() { 
    let fin = BufReader::new(File::open("/etc/hosts").expect("cannot open file")); 
    parse(fin.lines().map(|r| r.expect("file read failed"))); 

    let content: &'static str = "some\nlong\ntext"; 
    parse(content.lines()); 
} 
関連する問題