ムーブセマンティクスを忘れていた話。
Builderパターンで以下のように書いたところコンパイラにerror[E0507]: cannot move out of borrowed content
と怒られた。
enum Method {
Get,
Post,
}
struct Client {
method: Method,
}
struct ClientBuilder {
method: Method,
}
impl ClientBuilder {
fn new() -> Self {
ClientBuilder {
method: Method::Get,
}
}
fn method(&mut self, method: Method) -> &mut Self {
self.method = method;
self
}
fn finalize(&self) -> Client {
Client {
method: self.method,
}
}
}
ClientBuilder.finalize()
で、self.method
の所有権を失ってしまうために怒られていた。
対応
列挙型Method
にCopy
トレイトを実装することで解決できる。そのためのアトリビュートもある。
#[derive(Copy, Clone)]
enum Method {
Get,
Post,
}
認識の修正
この対処方法はドキュメントにも書いてある。
このケースは、以下の認識で書いたために引っかかってしまった。
- enumの中身は数値だろう、すなわち、プリミティブな値だろう
- プリミティブな値であればコピーされて所有権を失わないだろう
この認識を改めていく。
enumの中身はプリミティブな値ではない
ドキュメント 列挙型 より
列挙型の値(ヴァリアントと呼ぶ)は構造体の定義である。
Unit-like構造体であったり、名前付きフィールドを持つ構造体であったり、タプル構造体であったり。
enum Message {
Quit,
ChangeColor(i32, i32, i32),
Move { x: i32, y: i32 },
Write(String),
}
そもそもプリミティブな値だから所有権を失わないのではない
ドキュメント 所有権 より
全てのプリミティブ型は Copy トレイトを実装しているので、推測どおりそれらの所有権は「所有権ルール」に従ってはムーブしません。
Copyトレイトを実装しているから、所有権を失わない。
所感
見事にドキュメントで説明される事柄を踏み抜いた