私的Rust学習メモ3(Trait Generics Closure)


Trait

  • Structが実装するべきmethodを定義できるもの。
  • Object指向におけるInterfaceに近い。
  • Traitにはメソッドの型定義とデフォルト実装を書く
  • デフォルト実装の中でデフォルト実装のないメソッドを呼ぶことも可能。
  • このおかげで例えばIteratorTraitについてはnextだけ実装すればかなりの機能が使えるようになる。
  • 各メソッドごとに型情報をジェネリクスで足すことによって、使用可能なメソッドを絞り込むことができる。 (IteratorTraitを実装しており、かつIteratorのItemの型がSumを実装しているとsumが使えるようになるなど)
  • 実装するときは、impl Trait名 for Struct名{}
  • 言語に組み込まれている +<といった演算子も、特定のTraitを実装すると自分で定義したStructで使用可能になる。
  • Traitの実装を定義できるのは、StructまたはTraitと同じモジュールのみ。全然関係ないところで勝手に定義することはできない。
  • Trait側で実装したものについては、TraitをuseしなければStructの挙動に影響を与えない。

Generics

型Generics

  • コードを書く側から見た挙動は大体多言語のGenericsと同じ
  • ただし、コンパイルされる際には実際に利用される型それぞれについてコードが生成される。 (javaなどのコンパイル時のチェックにしか使わないものとは異なる)
  • Genericsは T<ジェネリクス名>という形で定義していくが、Whereで後に切り出すこともできる
  • 命名規則はよくあるパターンで、T,U...

LifeTimeGenerics

  • 関数の戻り値だったりStructのフィールドに借用してきたものがある場合、ライフタイムの判定基準が一意に決まらない場合がある。このような場合はLifeTimeアノテーションを使う
  • LifeTimeアノテーションは'aというような形で宣言する。
  • 複数のフィールドや引数につけた場合、一番短いものが採用される(いずれかのライフサイクルが切れたら使えなくなる)
  • 命名規則は小文字aから。
  • なお、'staticはバイナリ上の値に対する参照のライフサイクル=>常に有効。固定文字列を返す場合などに使う。

Closure

Rustにおける無名関数のようなもの。
通常の関数と異なり、宣言時のScopeから見える変数を自分の中に閉じ込めることができるのでClosure。
(Rustの関数は関数中で定義しても関数外の変数にアクセスすることは原則できない)

関数との違い

  • シグネチャ 引数の書き方が |引数|である
  • 前述の通り、見えている変数をClosure内では利用可能
  • 型推論がより働く。変数として宣言して利用する想定で、スコープ外に出す前提ではないため。 引数の型や戻り値の型、引数が所有権取得なのか、mutな借用なのかimmutableな借用なのかも推論してくれる。