Rustの所有権や計算速度に関するメモ

# Rustの所有権

Rustはc++などとは異なり、あるオブジェクトの所有者は**ただ一つのみ**許される。

例えばこう言うことができない。

```cpp
int* x = new int[5];
// xに代入などの処理

// yに付け替え
int* y = x;

// この後何やかんや処理。

```

これだとx,y両方が配列の所有者になってしまって、xからもyからも解放ができてしまう。Rustはこれを許さない。

c++だとunique_ptrが所有権を限定するような機能を持つが、get()とかで他の関数に渡したら、何かあっても実行時エラーになる。Rustはコンパイルの時に怒られるため、より厳格なんだと思う。

# よくつまづく例

## 変更可能な参照

cppだと以下は実行可能。

```cpp:cpp
double original = 0.0;
double *reference = &original;
original += 1.0;
*reference += 1.0;
```

Rustでは同じようなものを書いてもコンパイル前に怒られる。

```rust:rust
let mut original = 0.0;
let reference = &mut original;
original += 1.0;
*reference += 1.0;
```

3行目の`original += 1.0;`がだめ。これは**値を借用している最中は元の値を使った操作ができない**ために起きる。
`reference`は`original`を変更可能な参照として作られる。Rustでは`reference`の寿命が尽きるまで`original`を使えない。なので、以下のようにすると実行できる。

```rust:rust
let mut original = 0.0;
let reference = &mut original;
*reference += 1.0;
original += 1.0;
```

3,4行目を反転させた。こうすると、この処理以降`reference`が登場しなければ、3行目の処理で`reference`の役割は終わって、借用していた所有権を`original`に返却する。わかりやすく書けばこう言うこと。

```rust:rust
let mut original = 0.0;
{
    let reference = &mut original;
    *reference += 1.0;
}
original += 1.0;
```

## ライフタイム

cppだとこうしたいことがよくある。(例: 木構造など)

```cpp:cpp
class Node{
  public:
    Node* child;
}
```

こうすることであるNodeから別のNodeに移っていくことができるが、Rustはこれを簡単には許さない。
この構造の場合、以下のような実装を行う可能性がある。

```cpp: cpp
Node node1;
Node node2;

node1.child = &node2;
```

すごくわかりやすくていいのだが、この場合node2の所有者は誰か疑問になってしまう。node1.childからも操作できてしまうし、もちろんnode2を直接操作することもできる。これはRustが許すはずがない。
また、スコープの関係でnode1よりも先にnode2が消えてしまうかもしれない。こう言うことをRustは厳しく取り締まっている。

ここで出てくるのがライフスパンで、寿命のようなもの。

```rust: rust
struct Node<'a> {
    child: &'a mut Node<'a>,
}
```

`<'a>`がライフスパンで、そもそもどの変数にもライフスパンはあるのだが、Node<'a>と書くことで、明示的にライフスパンに名前をつけて扱えるようになる。
この例だと、`struct Node<'a>`でNodeのライフスパンを'aということにしている。そのメンバ定義では`child: &'a mut Node<'a>`によって、childは親と同じ`'a`というライフスパンを持つNode型で、親と同じタイミングで解放される。そしてその型を同じく`'a`のライフスパンを持つ参照を使ってchildに当てはめる。

# iter().map()とiter_mut().for_each()とfor

あるベクトルの各要素に値を計算して入れる場合、v.iter().map().collect()とする方法、v.iter_mut().for_each()を使う方法、普通にfor文を使う方法がある。アルゴリズム的に使いづらいこともあるが、基本的にはどれが速いのか確かめてみた。

一応それぞれ使いやすいシーンが違うと思うので、できるだけ条件を合わせるため、計測範囲はベクトルの作成から完成までとする。

```rust: iter().map()
// 元の乱数列作成
let num = 100000;
let mut rng = rand::rng();
let rand_src = vec![0.0; num]
    .iter()
    .map(|_| rng.random::<f64>())
    .collect::<Vec<f64>>();

// iter().map()
let mut dur: time::Instant = time::Instant::now();
#[allow(unused)]
let rand_dst1: Vec<f64> = rand_src
    .iter()
    .map(|x: &f64| x + rng.random::<f64>())
    .collect::<Vec<f64>>();
let dur_iter: time::Duration = dur.elapsed().clone();
```

```rust: iter_mut().for_each()
// 元の乱数列作成(省略)
// for_each()
dur = time::Instant::now();
#[allow(unused)]
let mut rand_dst2: Vec<f64> = rand_src.clone();
rand_dst2.iter_mut().for_each(|x| *x += rng.random::<f64>());
let dur_fe: time::Duration = dur.elapsed().clone();
```

```rust: for
// 元の乱数列作成(省略)
// for
dur = time::Instant::now();
#[allow(unused)]
let mut rand_dst3: Vec<f64> = vec![0.0; num];
for x in rand_dst3.iter_mut() {
    *x += rng.random::<f64>();
}
let dur_for: time::Duration = dur.elapsed().clone();
```

要素数を変えて10回ずつ平均をとった。

||iter().map() [us]|for_each() [us]|for [us]|
|-|-|-|-|
|10|1.084|1.669|1.456|
|100|7.916|7.251|8.915|
|1000|71.294|66.125|75.750|
|10000|765.789|667.123|745.458|
|100000|7353.084|7104.751|8084.876|

forが平均的にみて遅そうだが、要素数ごとの時間変化はどれも同じくらいで、特にどれを使ったからといって速さに差は無さそう。