0

In the following code, the implementation of show_author() is the same for Post and PostDraft.

Is it possible to de-duplicate it and implement it directly in the trait, or in another form, so that it wouldn't have to be written twice?

trait PostAuthor {
    fn show_author(&self) -> String;
}

struct Post {
    author: String,
}

struct PostDraft {
    author: String,
}

impl PostAuthor for Post {
    fn show_author(&self) -> String {
        &self.author
    }
}

impl PostAuthor for PostDraft {
    fn show_author(&self) -> String {
        &self.author
    }
}

When trying to replace the method signature with the actual implementation in the trait, the following error shows, indicating that the trait obviously doesn't know (and rightly so) about any author field:

error: attempted to take value of method `author` on type `&Self`
 --> src/lib.rs:5:15
  |
5 |         &self.author
  |               ^^^^^^
  |
  = help: maybe a `()` to call it is missing? If not, try an anonymous function

In a hypothetical purposefully-invalid imaginary Rust code, a solution would be to simply declare the implementation for the two structs at once:

impl PostAuthor for Post, PostDraft {
    fn show_author(&self) -> String {
        &self.author
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jivan
  • 21,522
  • 15
  • 80
  • 131
  • What differentiates a `Post` from a `PostDraft`? – Schwern May 07 '18 at 22:10
  • I believe your question is already answered by the answers of [Implementing a trait for multiple types at once](https://stackoverflow.com/q/39150216/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this as already answered. – Shepmaster May 07 '18 at 22:12
  • @Schwern in this example, absolutely nothing. In reality, they don't implement the same field definitions and/or method implementations. And there are more than two. The only rigorously common part is the `show_author` method, and it's more complicated IRL, therefore I'd like to avoid duplicating it. – Jivan May 07 '18 at 22:12
  • 1
    @Shepmaster this was not the answer I was _hoping for_, but that was the actual answer indeed. Actually it makes sense, and as one of the answer mentions, the code above calls for refactoring. Thanks for your reactivity. – Jivan May 07 '18 at 22:21
  • I feel like implementing `Post` and `PostDraft` as separate structs is the real problem here. "Draft" (or "published") might better be a trait. – Schwern May 07 '18 at 22:23
  • @Schwern it makes sense — however I'm trying to follow the example from the Rust Book where they go through a variant of the state pattern using types as state, hence the two different types here — https://doc.rust-lang.org/beta/book/second-edition/ch17-03-oo-design-patterns.html – Jivan May 07 '18 at 22:25
  • 1
    @Schwern it is a duplicate as it is phrased; you'd need to perform substantial editing to make *this* not a duplicate. Perhaps you need to self-ask/answer a question that is phrased however you need it be to answer it. – Shepmaster May 07 '18 at 22:37
  • @Schwern actually this part of the Rust Book is precisely about using several types to model state, instead of putting state in a given, unique type. I suggest you read through the link I provided if you're interested, as it gives quite a surprising perspective on that, at least as I found. – Jivan May 07 '18 at 22:40
  • 1
    @Jivan I see where you're at in the example now. I think in this instance rather than adding more String fields to all the structs, you'd create a new struct like `struct Content { body: String, author: String }` and have everything use that. `struct DraftPost { content: Content }` and `struct Post { content: Content }`. – Schwern May 07 '18 at 22:43
  • 2
    @Schwern that's exactly what I ended up doing — it seems to be the most natural way to do that, effectively – Jivan May 07 '18 at 22:45

0 Answers0