2020年12月22日から2020年12月25日 のRustの勉強記録

TRPL pp. 303-324

13.1.3

クロージャやクロージャの呼び出し結果の値を保持する構造体を作る

  1. 結果の値が必要な場合
    1. その構造体に格納されている値があるかを確認
      1. あったら、それを使う。(クロージャを実行しない)
      2. なければ、クロージャを実行し、その結果の値をキャッシュする

これはメモ化、遅延評価と呼ばれるパターンで、残りのコードは結果を保存し再利用する責任を追わずに済む。

クロージャを保持する構造体を作成したい

クロージャを変数に直接保存する代わりに、クロージャを保持する構造体の新規インスタンスを保存する。

13.1.4

Cacher実装で課題になること: 他の文脈での再利用性

  1. 常にvalueメソッドの引数argに対して、同じ値を想定しており、更新できない。
    1. -> ハッシュマップを保持するようにしよう
  2. 引数の型、返り値の型が固定で、柔軟ではない
    1. -> ジェネリックな引数を導入するようにしよう

13.1.5

クロージャは:

クロージャの環境から値をキャプチャする3つの方法

所有権を奪うことをクロージャーに強制したいなら、引数リストの前にmoveキーワードを付ける

Fnトレイトのどれかを指定するほとんどの場合のプラクティス:

  1. Fnから始める
  2. コンパイラがFnMutFnOnceが必要な場合は教えてくれる

環境をキャプチャできるクロージャが関数の引数として有用な場面はイテレータ

13.2

イテレータパターンにより、一連の要素に順番に何らかの作業を行うことができる。

イテレータ:

イテレータの生成とその使用は別個であるが、forでまとめてもよい。

13.2.1

Iteratorトレイトは以下のようなものであり、1つのメソッドのみを定義することを実装者に要求する。それはnext

pub trait Iterator {
    type Item
    fn next(&mut self) -> Option(Self::Item)
}

Item型がイテレータから帰ってくる型になる。これを関連型と言う。

なお、nextは直接呼ぶことも可能。

next:

iter:

13.2.2

Iteratorトレイトは、デフォルト実装のある多くの異なるメソッドがある。

nextを呼び出すメソッドは、イテレータを消費することから、消費アダプタ(consuming adaptor)と呼ばれる

例: sumメソッド:

13.3

イテレータアダプタ

イテレータアダプタの例: map(クロージャ)

13.3.1

filter

13.3.2

イテレータの作成。ベクタ、ハッシュマップなど、コレクション型からできる。

Iteratorトレイトを自分で実装することでしたいことをなんでもするイテレータを作成できる。必要な定義の提供はnextメソッドのみ。

デモ:

impl Iterator for SomeStruct {
    type Item = 'a;
    fn next(&mut self) -> Option<Self::Item> {
        ...
    }
}

これでnextメソッドも他のIteratorトレイトメソッドを使用することができるようになる。

デモで使っているzipは、入力イテレータのどちらかがNoneを返したら、Noneを返す。

13.4.1

やりたいこと: 非効率なclone呼び出しを除外したい

疑問: なぜcloneを使っていたか?

方法: イテレータでどうするか?

13.4.1.1

env::args:

libのシグニチャを更新する:

本体を更新する:

添え字アクセスをやめ、添え字の場合の長さのチェックをやめ、nextメソッドを使い、Some/Noneでチェックする

13.4.2

イテレータアダプタメソッドを使用すれば、可変な状態の良を最小化し、(イテレータアダプタとそのやっていることの間隔を掴めば、)コードが明瞭化され、ループの高難度の目的に集中できる。

いろんなループを少しずつ弄んだり、新しいベクタを作ったりということをしなくて済む。

イテレータアダプタメソッドを使うか、ループを使うかは、スタイルやパフォーマンスの問題がある。