2017-12-30 36 views
1

カウントするときにイテレータが消費されるようです。同じイテレータを使用してカウントし、それを反復するにはどうすればよいですか?カウントと繰り返しに同じイテレータを使用するにはどうすればよいですか?

私はファイル内の行を数えてから印刷しようとしています。私はファイルの内容を読むことができる、私は行数を数えることができるが、私はもはや内部カーソルがイテレータの終わりにあるかのように行を繰り返し処理することができません。

use std::fs::File; 
use std::io::prelude::*; 

fn main() { 
    let log_file_name = "/home/myuser/test.log"; 
    let mut log_file = File::open(log_file_name).unwrap(); 
    let mut log_content: String = String::from(""); 
    //Reads the log file. 
    log_file.read_to_string(&mut log_content).unwrap(); 
    //Gets all the lines in a Lines struct. 
    let mut lines = log_content.lines(); 
    //Uses by_ref() in order to not take ownership 
    let count = lines.by_ref().count(); 
    println!("{} lines", count); //Prints the count 
           //Doesn't enter in the loop 
    for value in lines { 
     println!("{}", value); 
    } 
} 

Iteratorresetメソッドを持っていないが、内部カーソルが、カウントした後、イテレータの最後にあるようです。もう一度log_content.lines()を呼び出して新しいLinesを作成することは必須ですか?または内部カーソルをリセットすることはできますか?今のところ、私が見つけたこの問題を回避するには、新しいイテレータを作成

されています:

use std::fs::File; 
use std::io::prelude::*; 

fn main() { 
    let log_file_name = "/home/myuser/test.log"; 
    let mut log_file = File::open(log_file_name).unwrap(); 
    let mut log_content: String = String::from(""); 
    //Reads the log file. 
    log_file.read_to_string(&mut log_content).unwrap(); 
    //Counts all and consume the iterator 
    let count = log_content.lines().count(); 
    println!("{} lines", count); 
    //Creates a pretty new iterator 
    let lines = log_content.lines(); 
    for value in lines { 
     println!("{}", value); 
    } 
} 

答えて

3

countを呼び出すと、イテレータが実際に実行されるまで繰り返されます(つまり、next()Noneを返します)。

あなたがby_refを使用して、イテレータを消費防ぐことができますが、イテレータはまだその完了(by_refは実際にちょうどイテレータへの変更可能な参照を返し、Iteratorも変更可能な参照のために実装されています。impl<'a, I> Iterator for &'a mut I)に駆動されます。

これは、イテレータに完了後に再利用したい他の状態が含まれている場合でも、この場合には有効です。

イテレータをフォークすることもできます(この場合は、副作用がなければCloneを実装することがあります)。ただし、この場合再作成はちょうど良い方法です(イテレータを作成する時間はほとんどの場合、 nextを直接的または間接的に呼び出すことによって運転する場合にのみ行われます)。

いいえ(この場合)はリセットできません。新しいものを作成する(または使用する前に複製する)必要があります。

+0

あなたの答えをありがとう。私はイテレータのクローン作成については考えましたが、この場合は新しいイテレータを作成するのと同じですが反復にはコスト(「for」または「count」のいずれか)があることを理解していますが、反復する場合にのみコストがあり、必要な場合にのみ反復します。しかし、再度反復が不可能な場合は、新しい反復子を作成します。 – AnthonyB

-4

コンピュータサイエンスのイテレータは、その条件指定した特定のセットを反復処理し続けループと同じものではありません満たされなければならない。イテレータは反復処理を行うと言うだけの処理を行います。通常、与えられたデータセットを1回だけ通過します。単純な反復とは異なる機能を望むならば。クラスを定義し、それにあなたが望む顧客行動を与えます。それはOOPの継承がどこに来るかです。あなたが望む機能を持っているかどうかを判断するために、反復する言語が何であっても反復子のデフォルトの振る舞い(データの先頭に戻す)は、クラスのAPIを見直す必要がありますあなたは使用しています。

+0

答えていただきありがとうございますが、Rustにはクラスも継承もなく、構造体しかありません。この場合、私は 'Iterator'を実装する' Lines'構造体を持っています。だから、値を指す内部カーソルがあり、ループがイテレーターを反復し、イテレーターが内部カーソルを移動して次の値を指すと思います。多くの言語で、カーソルをリセットする必要なしにカウントすることは可能ですが、Rustではカーソルが移動します。私が知らないのは、新しいイテレータを作成する必要がある場合、または同じイテレータを使用できるかどうかです。 – AnthonyB

+0

実際それは間違っています。 Rustでは、イテレータはほぼすべての点でforループと同じです。イテレータはforループとほぼ同じマシンコードにコンパイルされます。 https://doc.rust-lang.org/book/second-edition/ch13-04-performance.html – StarSheriff

+0

FNサイクル(自己) - > 自己サイクル :クローン、 [ - ] 繰り返しAN無限に反復子。 Noneで停止するのではなく、最初からイテレータが再び開始されます。再度反復した後、最初から再び開始されます。そしてまた。そしてまた。永遠に。それは間違いではありませんIteratorは何かを繰り返すことを想定しています。私のポストの最初の行を読んでください。イテレータを何度か反復処理したい場合は、インクルードされた機能を使用するか、自分で定義する必要があります。 –

2

繰り返しのコストがかかる可能性があるため、反復子は通常2回反復できません。 str::linesの場合、各反復では文字の次の行末を見つける必要があります。これにはいくらかの費用がかかります。イテレータは後で再利用できるようにその位置を単純に保存できると主張できますが、そのコストはさらに大きくなります。 Iteratorの中には、反復するのがさらに高価なものがありますので、実際には2回することは望ましくありません。

しかし、ほとんどのイテレータは簡単に再作成できます(ここではstr::linesをもう一度呼び出します)。clone dです。どのように反復子を再作成しても、2つの反復子は一般に完全に独立しているため、繰り返すことで価格を2回支払うことになります。

具体的には、行を数えるだけで非常に高価な操作になるので、メモリに収まる文字列を使用しないでください。これが当てはまると思われる場合は、まずLines::countというアルゴリズムを書くことは、Linesの主な目的は行を繰り返すことなので、可能な限り最適化されていない可能性があります。

+0

あなたの答えをありがとう。イテレータの反復にはコストがかかりますが、私がステファンに言ったように、私は必要な場合にのみスロートを反復します。この場合は反復するのが私の選択です。しかし、私はそれが必要でないときに私たちが反復によってパフォーマンスを浪費するのを阻止するためだと思います。それで、私がやるべきことなら、かなり新しいイテレーターを作ります。 – AnthonyB

関連する問題