下記のRustドキュメントのリスト17-15のコードが一部理解できないので教えてほしいです。
The Rust Programming Language 日本語版 - オブジェクト指向デザインパターンを実装する#記事の査読を要求すると、状態が変化する
Rust
1impl Post { 2 // --snip-- 3 pub fn request_review(&mut self) { 4 if let Some(s) = self.state.take() { 5 self.state = Some(s.request_review()) 6 } 7 } 8} 9 10trait State { 11 fn request_review(self: Box<Self>) -> Box<State>; 12} 13 14struct Draft {} 15 16impl State for Draft { 17 fn request_review(self: Box<Self>) -> Box<State> { 18 Box::new(PendingReview {}) 19 } 20} 21 22struct PendingReview {} 23 24impl State for PendingReview { 25 fn request_review(self: Box<Self>) -> Box<State> { 26 self 27 } 28}
分からない箇所は大きく分けて2つです。
impl Post
のrequest_review
メソッドでSome(s)
とself.state.take()
を使用している理由State
トレイトのrequest_review
メソッドの引数がself: Box<Self>
の理由
1番目について、3つの疑問に分かれます。
まず、self.state = self.state.request_review();
のように直接代入するコードはなぜだめなのでしょうか。ドキュメントでは、構造体は未代入のフィールドを許可しないから先述のコードは動作しないと記載があるのですが、未代入のフィールドなどないように思えるので、意味が良く分かりませんでした。
また、Some(s)
を使用する方のコード(元のコード)に関しても、self.state.take()
の代わりにself.state
を使えばSome(s)
でムーブすると思ったのですが、実際には下記の様なムーブできないエラーになりました。なぜなのでしょうか。
Rust
1error[E0507]: cannot move out of `self.state.0` which is behind a mutable reference 2--> src\lib.rs:23:26 323 | if let Some(s) = self.state { 4| - ^^^^^^^^^^ help: consider borrowing here: `&self.state` 5| | 6| data moved here 7| move occurs because `s` has type `Box<dyn State>`, which does not implement the `Copy` trait
さらに、上記のエラーから参照なら大丈夫かと思いself.state.take()
の代わりに&self.state
を使用してみたのですが(前提としてBox
への参照が許されているのか分かりませんが)、下記のようなエラーになりました。s.request_review()
でムーブが発生するとなぜダメなのでしょうか(冒頭に提示した大きく分けた2つ目の疑問でも言及しているのですが、そもそもなぜここでムーブが発生するのか良く分かりません)。
Rust
1error[E0507]: cannot move out of `*s` which is behind a shared reference 2--> src\lib.rs:24:31 324 | self.state = Some(s.request_review()) 4| ^^---------------- 5| | | 6| | `*s` moved due to this method call 7| move occurs because `*s` has type `Box<dyn State>`, which does not implement the `Copy` trait 8note: this function takes ownership of the receiver `self`, which moves `*s` 9--> src\lib.rs:30:23 1030 | fn request_review(self: Box<Self>) -> Box<dyn State>; 11| ^^^^
2番目について、2つの疑問に分かれます。
まず、なぜ&self
ではなく、self
であるのでしょうか。ドキュメントではBox<Self>
の所有権を奪い、古い状態を無効化するためと記載があるのですが、この文章の意味が良く分かりませんでした。s.request_review()
が実行されると、メソッド実行開始の時点でsの所有権がselfにムーブし、そのままメソッドの終わりでドロップするので消滅するという意味でしょうか?また、なぜ古い状態を無効化する必要があるのでしょうか。単に新しい状態を戻り値で返すだけでよいのではと思ったのですが。(不要になったBox
のメモリが長く残ってしまうのを防ぐためでしょうか?)
次に、Box<Self>
の指定が必要な理由です。ドキュメントではBox<Self>
にすることで、Box
に格納された状態からのみ呼び出せるようになると記載がありますが、なぜその制限が必要なのでしょうか。単純に誤った使い方をした場合にコンパイルエラーを出すためでしょうか。
長くなってしまいますが、よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/09/21 12:42