Vectorから値を取り出そうとしてみる
fn main() {
#[derive(Debug)]
struct Num {
num: u8
}
let zero = Num{num: 0};
let one = Num{num: 1};
let two = Num{num: 2};
let vector = vec![zero, one, two];
let zero = vector[0];
println!("{:?}", zero);
}
これはコンパイルに通りません。
error[E0507]: cannot move out of indexed content
indexing
vectorの0番目の要素を取り出そうとして、vector[0]
と書きました。
そもそもこの書き方はVector
が提供しているものではないのです。
[]
を使った方法はVector
がIndex
トレイトを実装しているために使えるものです。
std::ops::Index - Rust
Vector
の値を取り出すメソッドにはget
が定義されています。
getとindexingの違い
get
を使って次のように書き換えるとコンパイルに通ります。
fn main() {
#[derive(Debug)]
struct Num {
num: u8
}
let zero = Num{num: 0};
let one = Num{num: 1};
let two = Num{num: 2};
let vector = vec![zero, one, two];
let zero = vector.get(0);
println!("{:?}", zero);
}
Some(Num { num: 0 })
この違いはなんでしょうか。
indexの挙動
indexの挙動は次のようになります。
- 要素が
Copy
を実装していればcopyした値を返す -
Copy
が実装されていない場合は、値を返す
Num
はCopy
を実装していないため、indexで要素を取得しようとすると値がそのまま返されます。
すると、vector
の1つめの要素のNum
の所有権が、vector
からzero
に移ることになります。
しかし、Vector
の要素の一部分だけ所有権がmoveすることは許されていいないため、コンパイルに通らないようです。
getの挙動
get
は指定された場所にある要素の参照を返します。
そのため、zero
は要素の参照になるため、とくに問題はないのです。
copyを実装している場合
indexを利用しても、要素がCopy
を実装していれば、copyされた値が返されるので所有権の問題は生じません。
以下はコンパイルに通ります。
fn main() {
println!("{:?}", zero);
let vector = vec![0, 1, 2];
let zero = vector[0];
println!("{}", zero);
}
参考
rust - What does "cannot move out of indexed content" mean? - Stack Overflow
std::vec::Vec - Rust
std::ops::Index - Rust