🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

641閲覧

Rustのスカラー値を要素に持つ配列に対する処理について

TS01

総合スコア3

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2020/12/18 21:31

Rustの、スカラー値を要素に持つ配列に対して、値を取り出す際に参照(&)をする理由がわかりません。
Rustの配列は、格納されている型がスカラー値の場合、スタック領域に保存されるため、その配列に対して値を取得したりする場合は、常にコピーが行われている。
というのが今の私の理解です。

そのため、配列に対してスライスを使う場合に参照(&)を行う理由がわかりません。
(以下の&a[1..3]の部分は、a[1..3]ではないのかな。。?と思っています。)

Rust

1let a = [1, 2, 3, 4, 5]; 2 3let slice = &a[1..3];

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

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 03:06

編集2020/12/19 04:54
tatsuya6502

総合スコア2046

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TS01

2020/12/19 07:41

配列から要素を取り出す操作と、配列の要素に対するスライスを作る操作は別の操作なのですね。 よくわかりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問