Rustの所有権まわりの基礎まとめ

Rustの所有権/借用周りについて混乱したので勉強がてら整理しました．

# Rustの変数モデルと所有権
* Rustの変数管理モデルを値型か参照型か分類すると，**値型**になる．これはC++などと同じでPythonやHaskellなどとは違う．どちらかというと抽象度を犠牲にして実行速度を取るモデル．
* Rust最大の特徴は，実行速度を犠牲にしない範囲でできるだけ人間にやさしい変数管理を実現するための**所有権システム**を導入していること．コンパイラが変数の取り扱いを静的にチェックして値のread/writeが散らからないようにしてくれる．


# 所有権システムのご利益
色々言われているが，副作用の局所化なんじゃないかと思っている．例えば，下のコードのように同じ変数のmutableな参照とimmutableな参照を場所によって混ぜて利用していても，immutableな参照が生きている間は参照透過性が保証される（そういうコード以外は弾かれる）：

```rust
let mut value = MyValue::new();
let mut obj = MyObj::new();
obj.impure_method(&mut value);  // mutableな参照を使った計算
obj.pure_method(&value);  // immutableな参照を使った計算　<- このメソッドの実行中にvalueが書き換わらないことが保証される
```
雑に言えばC++のconst参照にHaskellの参照透過性がついたようなもので，人間の認知負荷をかなり下げてくれる（と期待している）．

# 所有の基本8形態
* Rustの所有権システムは**変数の束縛と参照**を通じて変数のread/writeの権限を管理する．
* 間接的なものまで含めると基本的な所有の形態は３種８形態に分かれる[^1]．
    1. ２つの束縛: immutable/mutable bind
    2. ２つの参照: `&T`, `&mut T`
    3. ４つの間接参照: `Box`, `Rc`, `Cell`, `RefCell`
    

## 1. 束縛（=所有）
Rustを学んでまず出会うのは，２つの変数束縛だろう．

```rust
let x = MyStruct::new();  // immutable変数の束縛
let mut y = MyStruct::new();  // mutable変数の束縛
```

`x` には値を変更する権限がなく， `y` にはその権限がある．本当の意味での所有はこの二種類だけだ．Rustの束縛は排他的で，同時に２つ以上の名前が同じメモリアドレスの値を束縛しないことが保証されている．すでに存在する値に対して２つ目の束縛が作られる瞬間，値の型に応じてcopyかmoveのどちらかが行われる：

```rust
let z = y;
```
 `MyStruct` がCopy traitを実装している場合，copyが発生する．このとき `z` に `y` の値のコピーが割り当てられ，`y` と `z` は異なるメモリアドレスに対応することになる． そうでない場合にはmoveが発生し，単にそれ以降古い方の名前 `y` を使うことができなくなる． 
このように変数にアクセス可能な窓口を単一にすることで，データを破棄するタイミングが静的かつ安全に決定できる．


## 2. 参照（＝借用）
排他的な所有の仕組みは予期しない値の変更を防ぐ上でとても役に立つが，それだけでは処理の部品を組み合わせて全体を組み立てていく現代のプログラミングに沿わない点がある：

```rust
fn foo(x: MyStruct)
{
    // xを使った処理
}

fn main()
{
    let x = MyStruct::new(); // Copy traitを実装していない構造体
    foo(x);  // xがfooの引数に束縛されたのでmoveが発生
    println!("{}", x); // エラー！ xという名前はもはや使えない
}
```

コピーすることなしに `x` をもう一度使いたければ，いまのところ `foo` の返り値に `x` を再指定するしかない：

```rust
fn foo(x: MyStruct) -> MyStruct
{
    // xを使った処理
    return x; // xを返却
}

fn main()
{
    let x = MyStruct::new();
    let x = foo(x);  // 二度のmoveを経て所有権が戻ってくる
    println!("{}", x); // OK
}
```

しかしこのやり方はうまくない．引数がもっとたくさんあったらその分返り値をたくさん書かなければならないし， `x` はimmutable変数なので変更されることがないというのにまったく並列化ができない．

### 借用システム: 参照
そもそも`foo` が呼ばれている間は呼び出し元の `x` は変更されることがないのだから，一時的に `foo` が `x` を「借用」して，終わったら自動で返却するようにはできないか．
この点を補うのが**参照**とそれを管理する**借用システム**だ．Rustの参照は次のように `&` か `&mut` を前置して作ることができる：

```rust
let r = &x;  // immutable参照の束縛
let s = &mut y;  // mutable参照の束縛
```

Immutableな参照は参照先のreadのみが許されており，mutableな参照はそれを通して参照先のread/writeができる．どちらの場合も，`*`を前につけることで参照先の値にアクセスすることができる：

```rust
*s += *r;
```

参照が作られている間，アクセス権がその参照へと「借用」されている．そのため一時的に元の変数のmoveやwriteができなくなる（mutable参照の場合はreadも不可）が，参照がスコープを抜けて消滅すれば所有権も元に戻る：

```rust
let x = MyStruct::new();  // Copyを実装していない構造体
{
    let r = &x;
    // let z = x;  // NG (rが存在する間にxのmoveを試みている)
}
let z = x;  // OK (rは存在しない)
```

面白いことに，immutable参照の再束縛はcopyになるが，mutable参照の再束縛はmoveになると定められていると考えると辻褄が合う[^3]．これによって（自動的に）同じ変数のimmutable参照は複数存在しうるが，mutable参照は一つしか存在しないことが保証される．

### 借用システム: ライフタイム

借用システムが機能するためには，貸した権利の正しい返却を強制する仕組みが必要だ．返却したふりをして参照のコピーを隠し持たれると，それ以降所有者の単一性が失われてしまう．最初に挙げた例でも，返却されない参照はimmutable参照の透過性を破壊する：

```rust
obj.impure_method(&mut value);  // ここでobjがmut参照をコピーして隠し持つ
obj.pure_method(&value);  // このメソッドの実行中に前段のmut参照をうっかり触ってvalueを書き換える
```
Immutable参照であっても，返却しておかないと不正アクセスにつながるかもしれない：

```rust
let mut illegal = Illegal::new();
{
    let x = MyStruct::new();
    illegal.capture(&x);  // 内部変数に&xをcopy
}  // xは消滅
illegal.read_x(); // 内部変数をたどって存在しないはずのxのアドレスにアクセス???
```

このアクセス権の返却を保証する仕組みがライフタイム（寿命）だ．Rustでは変数束縛の排他性が成り立っているので，変数の寿命が尽きるのはそれを束縛する名前がなくなるときだ．そして変数束縛の寿命はスコープと呼ばれ，ブロックで管理されている：

```rust
{  // ブロックの始まり

    let a = /* expression */;
    // ...

}  //ブロックの終わり (ここでaは消滅する)
```
ここまではC++と同じ状況だが，rustはライフタイムをannotateできるところと，ライフタイムが必要に応じて伸縮するところ，そしてライフタイムの一致しない参照間のcopy/moveを静的に検知して咎めてくれるところが違う．例えば，参照透過性の例では

```rust
impl<'a> MyObj<'a> {  // MyObj型のlifetimeを'aとする
    fn impure_method<'b>(&mut self, value: &'b mut MyValue) {  // valueのlifetimeを'bとする
        // ...
        //self.x = x;  // エラー！　異なるライフタイムラベル間で代入を試みると怒られる
    }
}
```
のように構造体と引数で異なるlifetimeラベルを明示することで，valueへの参照がobj内にコピーされることを防ぐことができる：

```rust
obj.impure_method(&mut value);  // ここで&mut valueがobjのメンバにmoveされていないことが保証される
obj.pure_method(&value);  // &mut valueはもう使用されていないので，安全に&valueを使用できる
```
一方で，内部的に参照を保持しておきたければ両者のライフタイムを揃えれば良い．

```rust
impl<'a> MyObj<'a> {  // MyObj型のlifetimeを'aとする
    fn impure_method(&mut self, value: &'a mut MyValue) {  // valueのlifetimeを'aに揃える
        // ...
        self.x = value;  // （対応するメンバ変数があれば）参照を保持できる
    }
}
```
すると，逆にその後のimmutable参照の生成を咎めることができる：

```rust
obj.impure_method(&mut value);  // ここで代入した時点で&mut valueの寿命がobjのそれと揃う
obj.pure_method(&value);  // エラー！ objが生きている以上，&mut valueも生きており，mutable参照が生きているあいだは同じ変数の別の参照を作り出すことはできない
```
いずれにしても，コンパイルが通った暁には `&value` が生きている間に参照先の値が書き換わらないことが保証されている．

余談だが，もし `pure_method` が参照 `&value` を取らないメソッドだったらどちらのケースもコンパイルが通る．ライフタイムはメソッドの実装時にannotateすることになっているので，この場合呼び出しのコードを見ただけではどちらの挙動が選択されたのかわからない：

```rust
obj.impure_method(&mut value);
obj.pure_method();  // &mut valueは使用されているかもしれないし，使用されていないかもしれない．
```
コードの意図を明確にするために呼び出し側がライフタイムをannotateする方法が言語レベルでサポートされていれば便利だと思うが，今ところそのような方法はないようだ[^2]．

## 3. 間接参照
所有権システムと借用システムの上に実装されたスマートポインタのようなものたち．代表的には`Box`, `Rc`, `Cell`, `RefCell`がある．役割の違いとか，網羅性とかはまだあまり良くわかっていない．

[こちら](https://qiita.com/wada314/items/24249418983312795c08)がとても参考になりました．やる気が湧いたら別記事でまとめます．


[^1]: 最初の４つと後の４つはしばしば分けて紹介される．またスレッド安全に変数を管理する型として `Arc, Mutex, RwLock` があるが今回は触れない．この辺を参考にしている：https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/choosing-your-guarantees.html
[^2]: `obj.impure_method::<'a>(&'a mut value)` みたいな．代わりに`fn assert_no_borrow<T>(_: &T) {}` のような関数を定義しておいて，mutableな借用が終わっていてほしい場所に挿入するという方法を[教えてもらった](https://www.reddit.com/r/rust/comments/f7s14c/best_way_to_shrink_the_lifetime_of_references/fifvcv9?utm_source=share&utm_medium=web2x)．
[^3]: [実は細かいところで違う](https://stackoverflow.com/questions/32154387/why-is-the-mutable-reference-not-moved-here)が，そう考えておくとわかりやすい．