I'm reading chapter 17 of the Rust programming language, and I'm confused by the example in the 3rd section ("Object-Oriented Design Pattern Implementation").
Specifically listing 17-15, here.
There several confusing things with the code sample in this chapter, but the 2 main ones are:
-
Why is Option used in this Post struct?
pub struct Post {
state: Option<Box>,
content: String,
}impl Post {
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
} -
What is this syntax
self: Box<Self>
used here, and is it related to the use of Option? The text seems to hint that this is the case, but doesn't directly explain it at all.
trait State { fn request_review(self: Box<Self>) -> Box<State>; }
This syntax self: Box<Self>
for a method is confusing, since it's alluded in chapter 5 section 3 that methods are defined with self
, &self
or &mut self
as parameters. Seeing suddenly self: Box<Self>
as another way to define a method, made me think that methods could be defined in other ways, but trying to write self : &Box<Self>
failed to compile. This also doesn't match my intuition from C++. It looks like a form of pattern matching on self
, but apparently isn't (or else &Box<Self>
would also work).
The only place I found where self : Box<Self>
as a way to define a method was an an old stackoverflow question from 2014, but the book doesn't mention it nor any of the references.
So why did I try to write self : &Box<Self>
? Because it seems to me that if this were possible, it would make the Option in Post unnecessary, as well as the unwrapping / wrapping going on in the request_review method in the Post impl.
The way I understand this is something like this:
-
We want to use a trait object to get a polymorphic behavior at runtime.
-
To do this, we define the State as a trait, and put it inside a Box (in
struct Post
) to make it a trait object. -
We also define a method on the trait taking this trait object (request_review in the trait).
-
We couldn't use
&mut self
since then (I think) we wouldn't be able to return a polymorphic result in a Box - I checked and saw that in the trait implementation, if I used a&mut self
, I couldn't return another implementation, that is, this won't compile (I'm still not sure why exactly, isn't&mut self
implicitly of type Self, which is polymorphic?):trait State {
fn test_test(&mut self);
}
struct Draft {}
struct PendingReview {}impl State for Draft {
fn test_test(&mut self) {
self = &mut PendingReview{};
}
} -
So, the next best thing would be to use
self : &mut Box<Self>
since that would allow us to directly change what's inside the box without moving it. But that's not possible in a method, apparently. -
So, the next best thing is to use
self : Box<Self>
, which is a valid method syntax. -
However, this means the self is moved. We must move it somewhere so we wrap it up in an Option (possibly we could wrap it in any other struct? Why is Option important here? It doesn't seem to serve any purpose except as a place to move the boxed self to and from).
Am I right? Or did I miss something?