目次

Rustの勉強[イテレータその 4]

(更新: )ぎじゅつ

はじめに

#

NO IMAGEThe Rust Programming Language 日本語版 - The Rust Programming Language 日本語版
を読んでいる

  • 仮眠とったら次の日の朝になっていた
  • まあどうせ夜勉強するので前日分ということにする

お勉強

#

NO IMAGE入出力プロジェクトを改善する - The Rust Programming Language 日本語版
ここから

メモ

#
  • std::env::Argsはイテレータを返すから、それで再実装してみようって話だったな
impl Config {
    pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
        args.next();

        let query = match args.next() {
            Some(arg) => arg,
            // クエリ文字列を取得しませんでした
            None => return Err("Didn't get a query string"),
        };

        let filename = match args.next() {
            Some(arg) => arg,
            // ファイル名を取得しませんでした
            None => return Err("Didn't get a file name"),
        };

        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();

        Ok(Config {
            query,
            filename,
            case_sensitive,
        })
    }
}
  • 思ったより読める

  • イテレータがOptionのenumを返すから、nextで消費していく

  • 途中でなくなればErrにする

  • たしかにこっちのほうがしっくりくるか

  • イテレータアダプタを使って簡単に書けるっていってる

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }

    results
}

これが

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    contents
        .lines()
        .filter(|line| line.contains(query))
        .collect()
}

こう

  • えー何が変わった?

  • 多分予想だけどlines()がイテレータを返している気がする

  • let mut results = Vec::new();この記述がなくせるのも利点らしい

  • あー理解できたかも

    • いままでcollect()を使うときはVec<str>: =のような記述をしていた
    • これは戻り値でVec<&'a str>を指定しているからcollectでVec<str>に変換されるとう認識
    • スッキリ
  • 次はパフォーマンスの話

パフォーマンス比較: ループVSイテレータ

#
  • vs ダークライ
test bench_search_for  ... bench:  19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench:  19,234,900 ns/iter (+/- 657,200)
  • ベンチマークとったらイテレータのほうが速かったらしいぞ

  • さてなんでだろう

  • ここ単語を光らせるの無理かもしれん

イテレータは、Rustのゼロコスト抽象化の一つであり、これは、抽象化を使うことが追加の実行時オーバーヘッドを生まないことを意味しています。

  • よく聞くやつ

一般的に、C++の実装は、ゼロオーバーヘッド原則を遵守します: 使用しないものには、支払わなくてよい。
さらに: 実際に使っているものに対して、コードをそれ以上うまく渡すことはできない。

  • なるほどね
let buffer: &mut [i32];
let coefficients: [i64; 12];
let qlp_shift: i16;

for i in 12..buffer.len() {
    let prediction = coefficients.iter()
                                 .zip(&buffer[i - 12..i])
                                 .map(|(&c, &s)| c * s as i64)
                                 .sum::<i64>() >> qlp_shift;
    let delta = buffer[i];
    buffer[i] = prediction as i32 + delta;
}
  • このオーディオデコーダの例の意図がわからなくてずっと調べていた
  • ループの内部処理の一部もイテレータにすることによってパフォーマンス上がるよという理解をした
  • 回数が固定だとループ展開されてコンパイルされるのかも
  • それでオーバーヘッドが少ないよーという認識

まとめ

#
  • イテレータはパフォーマンスが良く、表現力もある
  • 逆にそれぐらいしかわからなかったな
  • これは実際にその瞬間に立たないとわからないという認識

次はここをサクっと読む
それこそ光る部分だけを記述する
NO IMAGECargoとCrates.ioについてより詳しく - The Rust Programming Language 日本語版