Rust の参照と借用

よく分からないので調べたことをまとめた。

## 所有権の厄介さ

i32 型のベクタオブジェクト v1、ベクタオブジェクト v2 の要素の総和を返す関数を例とする。

```rust
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let sum = sum_vector(v1, v2);
    println!("v1 and v2 sum is {}", sum);// <-- value moved here
    println!("v1 is {:?} ", v1); // <-- Error!!! value used here after move
    println!("v2 is {:?} ", v2); // <-- Error!!! value used here after move

}

fn sum_vector(v1: Vec<i32>, v2: Vec<i32>) -> i32 {
    let v1_sum = v1.iter().fold(0, |sum, x| sum + x);
    let v2_sum = v2.iter().fold(0, |sum, x| sum + x);
    v1_sum + v2_sum
}
```

ベクタオブジェクト v1 は`sum_vector`関数のスコープ内に所有権が移動しているため、`sum_vector`関数のスコープから外れた後に、呼び出し元の`main`関数内で参照するとエラーが出力される。v2 も同様である。

再度`main`関数内で使用するなら、`sum_vector`関数の戻り値にベクタオブジェクト v1 及び v2 を含める必要がある。

以下の例ではタプルに含めてで返すように`sum_vector`関数を変更した。

```rust
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let (v1, v2, sum) = sum_vector(v1, v2);
    println!("sum is {}", sum); // v1 and v2 sum is 21
    println!("v1 is {:?} ", v1); // v1 is [1, 2, 3]
    println!("v2 is {:?} ", v2); // v2 is [4, 5, 6]
}

fn sum_vector(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
    let v1_sum = v1.iter().fold(0, |sum, x| sum + x);
    let v2_sum = v2.iter().fold(0, |sum, x| sum + x);
    (v1, v2, v1_sum + v2_sum)
}
```

これは、嫌だ。

## 借用

以下のコードに書き換えることで、所有権の借用を行うことができる。

```rust
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let sum = sum_vector(&v1, &v2);
    println!("sum is {}", sum);
    println!("v1 is {:?} ", v1);
    println!("v2 is {:?} ", v2);
}

fn sum_vector(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
    let v1_sum = v1.iter().fold(0, |sum, x| sum + x);
    let v2_sum = v2.iter().fold(0, |sum, x| sum + x);
    v1_sum + v2_sum
}
```

1. sum_vector 関数に渡す変数を　`v1, v2` から `&v1, &v2`に変更。宣言自体は`v1, v2`のまま。
2. 引数の型を`Vec<i32>` -> `&Vec<i32>`

&T 型は参照と呼ばれ、リソースの所有権を借用する。

## 参照の種類

### 通常の参照

&T 型はイミュータブルなので変更できない。下記の例だとコンパイルエラーになる。

```rust
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let sum = sum_vector(&v1, &v2);
    ...
}
fn sum_vector(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
    v1.push(5); // cannot borrow as mutable
    ...
}
```

### &mut 参照

&mut T 型だと参照しているリソースを変更できる。これを前者を参照と呼ぶのと区別し、`&mut参照`と呼ぶ

```rust
fn main() {
    let mut v1 = vec![1, 2, 3];
    let mut v2 = vec![4, 5, 6];
    let sum = sum_vector(&mut v1, &mut v2);
    ...
}

fn sum_vector(v1: &mut Vec<i32>, v2: &mut Vec<i32>) -> i32 {
    v1.push(5);
    ...
}
```

&mut 参照は同じスコープでは行えない。下記の例ではコンパイルエラーになる。

```rust
fn same_scope(){
    let mut v1 = vec![1, 2, 3];
    let y1 = &mut v1; // v1の&mut参照開始
    y1.push(6);
    println!("v1 is {:?}", v1); // ここでv1を借用しようとするため、エラーになる
    // => cannot borrow `v1` as immutable because it is also borrowed as mutable
}
```

## 不正な参照

以下の例だと、スコープの終わりで変数 x が解放されるため、参照が不正となり、コンパイルエラーになる。

```rust
    let y: &Vec<i32>;
    {
        let x = vec![1, 2, 3];
        y = &x; // error[E0597]: `x` does not live long enough
    }
    println!("y is {:?}", y);
```

同じスコープでも、参照する変数が先に宣言されているとコンパイルエラーとなる。
これは後に宣言した変数から順に解放されるためである。下記の例だと変数 x -> y の順に解放されるので、y の参照が不正になる。

```rust
    let y: &Vec<i32>;
    let x = vec![1, 2, 3];
    y = &x; // error[E0597]: `x` does not live long enough
    println!("y is {:?}", y);
```

つまりこれなら大丈夫。

```rust
    let x = vec![1, 2, 3];
    let y: &Vec<i32>;
    y = &x;
    println!("y is {:?}", y);// => y is [1, 2, 3]
```