[Rust] &strとStringを理解しようと思ったらsliceやmutを理解できてないことに気づいた話

Rust入門メモ。

Rustは文字列を表す型として `&str` と `String` がある
これが、結構ややこしくて、どういうときにどっちを使うべきなのかがよくわからない

# 環境
OS: macOS High Sierra 10.13.3
Rust: rustc 1.26.0-nightly (c08480fce 2018-03-23)

# Rustの文字列型
[Rustの日本語Document: 文字列](https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/strings.html)

> Rustには主要な文字列型が二種類あります。&str と Stringです。 まず &str について説明しましょう。 &str は「文字列スライス」と呼ばれます。 文字列スライスは固定サイズで変更不可能です。文字列スライスはUTF-8のバイトシーケンスへの参照です。

> Rustには &str だけでなく、 String というヒープアロケートされる文字列もあります。 この文字列は伸張可能であり、またUTF-8であることも保証されています。 String は一般的に文字列スライスを to_string メソッドで変換することで作成されます。

https://qiita.com/Mizunashi_Mana/items/db88cb0bff002abce1ae

↑このQiitaの解説が一番わかりやすい

> Rustには文字列を表す型が二つあります。
> 一つはプリミティブ型のstr、もう一つが標準ライブラリが提供するStringです。といってもそれほど大した違いはありません。
> str型はu8のスライス、String型はu8のベクタと同じです。ただ両方とも、列の内容としてUTF-8しか許可していないというその一点だけが異なります。なので、実質並びに制限のある8byteの配列スライスとベクタです。strの方はプリミティブ型ですが、Stringの方は標準ライブラリの提供型なので実装が単純に見て取れます。

&str -> slice
String -> Vector

ということだ。

そもそも、sliceってちゃんと理解してないな…
だから、まずはsliceに関して理解していこうと思う

# sliceと配列とVector
https://qiita.com/Mizunashi_Mana/items/db88cb0bff002abce1ae#%E6%96%87%E5%AD%97%E5%88%97%E3%81%A8%E6%96%87%E5%AD%97%E5%88%97%E3%82%B9%E3%83%A9%E3%82%A4%E3%82%B9%E3%81%AE%E9%81%95%E3%81%84

ここにも書いてある

つまりsliceってのは、 配列とかVectorへの参照ということですかね。
sliceの型は `&[T]` なので、参照なのはわかる

ちなみに、文字列リテラルの型は `&’static str` 

ちなみに、Goのsliceとarrayの解説を見つけた
https://qiita.com/seihmd/items/d9bc98a4f4f606ecaef7

これを見ていて、いろいろ気になったので
Rustでどうなるのか気になる事をやってみることにした

## 配列の参照(スライス)を別の変数に束縛して、ポインタを確認してみる
```rust
let a: [i32; 2] = [1,2];
let b = &a;

// これは同じ
println!("{:p}", &a);
println!("{:p}", b);
```

```
0x7ffee9a76dd8
0x7ffee9a76dd8
```

## 配列を別の変数にそのまま代入してみる
```rust
let a: [i32; 2] = [1,2];
let b = a;

// これは違う
println!("{:p}", &a);
println!("{:p}", &b);
```

```
0x7ffee9a76eb8
0x7ffee9a76ec0
```

これはコピーされる(?)ので、参照先が違うようだ

## 配列を書き換える
```rust
let mut a = [1,2,3];
let b = a; // ここでコピーされる？
a[0] = 0;

println!("{:?}", a); // #=> [0, 2, 3]
println!("{:?}", b); // #=> [1, 2, 3]
```

これもコピーされるっぽいので、bは安全

## スライスを書き換える

```rust
let a = &mut [1,2,3];
let b = a;
a[0] = 0;

println!("{:?}", a); // #=> [0, 2, 3]
println!("{:?}", b); // #=> [1, 2, 3]
```

さて、これはコンパイルエラーになる

```rust
error[E0382]: use of moved value: `*a`
  --> main.rs:56:9
   |
55 |         let b = a;
   |             - value moved here
56 |         a[0] = 0;
   |         ^^^^^^^^ value used here after move
   |
   = note: move occurs because `a` has type `&mut [i32; 3]`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `a`
```

a自体が既にsliceなので、所有権はbに代入した時点でmoveされる(?)
つまり、bに代入した時点でaはもういじれなくなるということですかね

これは、めんどくさいように見えて、実は超安全だなぁ、と思った。
だって、書き換えられる人は一人だけで、bをこの先いじいじしてる間に、aを誰か別のやつが書き換える、なんてことが出来ないのだから
書き換えるどころか、参照することさえできない。printlnしようとするとコンパイルエラー。
(これ、かっこいいなぁ。)

mutableにしたい時は

```rust
let mut a = 1;
a = 2;
println!("{:?}", a);
```

こんな風に `let mut` って定義する
(ちなみに  `let mut a = 1;`  はwarningが出ます)

しかしながら、mutableなsliceを定義する時は

```rust
let mut a = &[1];
a[0] = 0;

println!("{:?}", a);
```

これだとコンパイルエラー

```
error[E0594]: cannot assign to indexed content `a[..]` of immutable binding
  --> main.rs:70:9
   |
70 |         a[0] = 0;
   |         ^^^^^^^^ cannot mutably borrow field of immutable binding

```

これは、何故か。

[答えはここに書いてある](https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/mutability.html) んだけど。

```rust
let mut x = 1;
```
これ(x)は、 `ミュータブルな変数束縛`

```rust
let mut x = 1;
let y = &mut x;
```
これ(y)は、 `ミュータブル参照` 

ということらしい。

> y はミュータブル参照へのイミュータブルな束縛であり、 y を他の束縛に変える(y = &mut z)ことはできません。 しかし、y に束縛されているものを変化させること(*y = 5)は可能です。微妙な区別です。

とのこと。

やってみよう。

```rust
let a = &mut [1];
a[0] = 0;

println!("{:?}", a);
```

aはimmutableなのに、aの要素を書き換えることが出来る。
これが、ミュータブル参照へのイミュータブルな束縛ということか。

```rust
let a = &mut [1];
a[0] = 0; // これはできる

a = &mut [2]; // これはできない

println!("{:?}", a);
```

`a`をmutableに束縛していないので、aという変数自体を書き換えることはできない。

んー、すっきりした！（気がする）

# &strとString

`&str` は `どっかへの参照`
`String` は `Vec<u8>`

なので、

- 参照だけでいい場合は、&strを使う
- 文字列の中身を書き換えたい場合はStringを使うとよい

ってことなんだろうか。

## &strで良い例

https://qiita.com/Mizunashi_Mana/items/db88cb0bff002abce1ae#%E9%96%A2%E6%95%B0%E3%81%AE%E5%BC%95%E6%95%B0%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6


```rust
fn puts(s: &str) {
    println!("{}", s);
}
```

受け取った文字列をただ標準出力に出力するだけ。
書き換えもしないので、ただただ参照を貰えばいい。

って書いてあると思うんですが

```rust

let a = "hoge".to_string();
println!("{:p}", &a);

puts(&a);

println!("{:p}", &a);
```

こんなことしてみると

```
0x7ffee61881d8
0x109e17018
0x7ffee61881d8
```

参照先が違う気がする。。。？
これは、何故だろう、、、

> パフォーマンス上ではスライスの作成はコピーが発生しませんが、

って書いてあるけど、本当にコピー発生してないのだろうか

```rust

fn puts(s: &String) {
    println!("{:p}", s);
}
```

こうすると、もちろん同じになる

```
0x7ffee3e521d8
0x7ffee3e521d8
0x7ffee3e521d8
```

んー。これは分からなくなってきた…

## Stringの方が良い例
https://qiita.com/Mizunashi_Mana/items/db88cb0bff002abce1ae#%E9%96%A2%E6%95%B0%E3%81%AE%E8%BF%94%E3%82%8A%E5%80%A4%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6

### 文字列を破壊的に書き換えたい場合

```rust

fn append_world(str: &mut String) {
  str.push_str(" World");
}

let mut string = "Hello".to_string();
append_world(&mut string);
println!("{}", string); // => Hello World
```

まぁ、これはたしかにその通りだな、と思った。
でも、そこまでシビアなパフォーマンスを要求されない限りは、
破壊的に変更したい事ってあまりなくて、大抵は新しい文字列を返したい気がする。

### 戻り値に文字列

これは、よくあると思う。

`&str` を返そうとするとコンパイルエラーになる

```rust
fn hoge() -> &str {
    "hoge"
}
```

これは、そもそも `”hoge”` は `&’static str` が型なので、型が合ってない

```rust
fn hoge() -> &str {
    let a = "hoge".to_string();
    &a
}
```

これは、型は合ってるけど、`&a` を返すということは、実体の `a` はこのscopeに生きているわけで
`a` の生存期間以上に長い生存期間の参照を返す事になるので、lifetime parameterが必要になるらしい。
(ライフタイムについては、また別途)

つまり、実体のStringをそのまま返しちゃうほうがいい、ということですかね。

# まとまらないまとめ

&strの引数の時に String ->  &str でコピーされるとしたら、あまり&strにうまみがない（？）
だとすると、全部Stringでいいのではなかろうかという気さえしてくる。

結局、どう使い分ければよいのか、はっきりと理解できずに終わってしまった。