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