Rustの、スカラー値を要素に持つ配列に対して、値を取り出す際に参照(&)をする理由がわかりません。
...
そのため、配列に対してスライスを使う場合に参照(&)を行う理由がわかりません。
配列から要素を取り出す操作と、配列の要素に対するスライスを作る操作は別の操作になります。そのため、それぞれの操作によって作られるものも異なります。前者は指定した配列要素の値がムーブまたはコピーされ、その値自体が得られます。後者は配列要素の値には変化がなく、要素の範囲を指すスライスが作られます。配列の一部がコピーされて新しい配列が作られるわけではありません。
スライスはポインタと要素数からなるデータ構造です。スライスのポインタは対象となる一連の要素の先頭アドレスを指します。スライスは参照の一種ですので、&
か&mut
の形でアクセスします。
値を取り出す操作の例
rust
1let a = [1, 2, 3, 4, 5]; // [i32; 5]型
2
3// i32型はCopyトレイトを実装しているので、配列要素の値がコピーされる
4let a1 = a[1];
5assert_eq!(a1, 2);
6
7let b = ["alice".to_string(), "bob".to_string()]; // [String; 2]型
8
9// String型はCopyトレイトを実装していないので、配列要素の値がムーブされる
10let b1 = b[1];
11// → コンパイルエラー
12// error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
13// move occurs because `b[_]` has type `String`, which does not implement the `Copy` trait
14
15// ムーブできないので、cloneすればOK
16let b1 = b[1].clone();
17assert_eq!(b1, "bob".to_string());
スライスを作る操作の例
rust
1let mut a = [1, 2, 3, 4, 5];
2let slice = &mut a[1..3];
3
4// スライスの先頭の要素に10を足す
5slice[0] += 10;
6
7assert_eq!(slice, &[12, 3]);
8
9// 元の配列の要素も同じように変更された
10assert_eq!(a, [1, 12, 3, 4, 5]);
Rustのチートシートというものがあり、スライスのデータ構造の図が載っていますので参考にしてください。
Pointer Payloadの&'a [T]
がスライスです。
追記
余談ですが、配列の一部をコピーするには以下のようにします。
配列の一部を別の配列へコピーする
rust
1let a = [1, 2, 3, 4, 5]; // [i32; 5]型
2let mut b = [0; 2]; // [i32; 2]型。0で初期化
3
4// スライスが指す一連の要素をmemcpyでコピーする
5b.copy_from_slice(&a[1..3]);
6
7assert_eq!(b, [2, 3]);
なおcopy_from_slice()
はスライスの要素がCopy
トレイトを実装しているときだけ使えます(ドキュメント) Copy
トレイトは実装していないがClone
トレイトなら実装しているときは、clone_from_slice()
を使います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/19 07:41