Open2

Rustを独自解釈していく

edaohedaoh

普段TypeScriptを書いているが、最近ほんの少しだけRustを書いている。
実際やってみるとかなり考え方(今っぽい言い方だとマインドモデル?)を切り替えないといけないような気がする。
ただ、「Rustってこういうものなんだな」という考えを述べるとまさかりを投げられそうなので、あくまで独自解釈としておく。

edaohedaoh

TypeScriptを長くやってきた人間にとってRustに特徴的なものは所有権とライフタイムだ。
所有権に関して理解している限りでは、所有権をやりとりするか、所有権ではなく読み取り専用の参照だけをやりとりするか、あるいは可変参照を渡す3つの形態がある。
考えてみれば当たり前だが、所有権を奪う関数に対して参照だけを渡すことはできない。可変参照でも駄目だ。
逆に参照しか要求しない関数なら好きに呼べる。
可変参照を要求する場合は、読み取り専用の参照では不十分で、逆は問題が無い。
つまり、所有権付き(?)変数と可変参照は参照の部分型として扱える。
では、所有権付き変数と可変参照の違いは何かと言えば、前者がムーブセマンティクスに則っており、イミュータブルな表現ができるのに対して、可変参照はいわゆる普通の変数だ。
安全性を考えると、なるべくムーブセマンティクスに沿いたい。
また、参照を渡す場合はライフタイムについても考えなければならない。
所有権を奪う場合と違って、参照は呼び出し側で変数が解放されているリスクがある。
だから、コンパイラにライフタイムを教える必要がある。
これも考えてみれば当たり前のことになる。
当たり前のことだが度々問題になるのは、それらがあくまでコンパイルタイムに判断されるため、書いてる側として「そんなつもりはない」ことを分かってはくれないからだ。
単純に書いている側のミスであればいいのだが、例えばクロージャを使う場面ではクロージャがいつ呼ばれるかコンパイラにはわからないため、一番厳しい制約を課すような解釈がされる。
所有権の話であれば、スコープ外の変数の参照は常に読み取り専用になる。
これをmapやfor_eachで使う場合、あくまで関数内でのみ呼ばれるクロージャに対する制約としては厳しすぎると感じるだろう。
しかしこの「関数内でのみ呼ばれる」という情報をコンパイラが知り得ないのだ。
対策は簡単で、単純なfor文に変え、プログラムの実行順序を明確にすればいい。
要するにRustは動的よりも静的なプログラミングパーツに一等席を与えている。
正直、動的なそれらが利便性や好みのために用意されているのだとしたら、かなり混乱を招く言語仕様だと思う。
だから、このスクラップではRustで優先して使うべきパターンやプログラミングパーツが何かを模索していくことで、混乱を少しでも緩和することを試みる。