ムーブセマンティクスを忘れていた話。
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トレイトを実装しているから、所有権を失わない。
所感
見事にドキュメントで説明される事柄を踏み抜いた