0

=== edit at 2018-04-28 10:17AM ===

Thanks for your answers, but when I follow your answers using Box<>, I found a situation where it won't work still.

https://play.rust-lang.org/?gist=211845d953cd9012f6f214aa5d81332d&version=stable&mode=debug

Bug info is:

error[E0038]: the trait `Entity` cannot be made into an object
  --> src/main.rs:20:5
   |
20 |     entities: Vec<Box<Entity>>
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Entity` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`

So I wonder what is cannot be made into an object? How can I fix the problem?

=== original answer ===
I want to implement a hierarchical structure like Java's interface/abstract class with a normal class:

trait Entry {
    fn new() -> Entry;
}

struct EntryA {}
impl Entry for EntryA {
    fn new() -> EntryA {
        // I want to return EntryA rather Entry here, just like dynamic dispatch in Java
    }
}

struct EntryB {}
impl Entry for EntryB {
    fn new() -> EntryB {
        // Another Entry struct
    }
}

Now I want to create a Vec or an array containing the Entrys:

fn create_an_array() -> [Something to write here] {
    let mut vec: Vec<Entry> = vec![];
    let ea = EntryA::new();
    let eb = EntryB::new();
    vec.push(ea);
    vec.push(eb);
    vec
}

When I use the Vec created by create_an_array(), all the elements I get can just show the Entry facade, rather than the subclass in detail.

However, the main problem is that when overriding the function, Rust considers not only the parameters but also the return type (Why you do that, Rust?!), so I cannot override new() in EntryA or EntryB because the function has a different return type than the Entry trait.

How do I deal with the problem of dynamic dispatch?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Ukonn Ra
  • 744
  • 6
  • 20
  • You must box your trait objects. – Boiethios Apr 27 '18 at 15:03
  • 1
    I think [Traits as a return value from a function](https://stackoverflow.com/questions/23437179/traits-as-a-return-value-from-a-function) is a considerably closer match. – trent Apr 27 '18 at 15:09
  • 1
    [Here's a working example](https://play.rust-lang.org/?gist=d2e2f8ee22ef8c8772f00878b25b3838&version=stable&mode=debug) applying a technique from the first marked duplicate. You could also make `new` return `Box` directly, or [take `new` out of the `Entry` trait entirely](https://play.rust-lang.org/?gist=6789c4a56974eb9b2c9c98127bb66123&version=stable&mode=debug); your example doesn't need the constructor to be part of the trait. – trent Apr 27 '18 at 15:40
  • 1
    It's best not to edit new questions into old questions. Feel free to ask a new question, but first, [take a look at this fixed version](https://play.rust-lang.org/?gist=92fda4088b2839a0effdf4b1dd16383b&version=undefined&mode=undefined). You can't ever have an object of type `Entity`, because `Entity` is an unsized type and unsized types always have to be behind some kind of pointer (see also [this question](https://stackoverflow.com/questions/45116984/the-trait-cannot-be-made-into-an-object)). – trent Apr 28 '18 at 14:26
  • 1
    Besides, your second issue was *already addressed* [by a duplicate](https://stackoverflow.com/questions/38159771/why-can-a-trait-not-construct-itself). – Shepmaster Apr 28 '18 at 15:13

0 Answers0