Are polymorphic variables allowed?

Yes, but not that easily. What you’ve written there is that animal should be a variable of type Barks, but Barks is a trait; a description of an interface. Traits don’t have a statically-defined size, since a type of any size could come along and impl Barks. The compiler has no idea how big to make animal.

What you need to do is add a layer of indirection. In this case, you can use Box, although you can also use things like Rc or plain references:

fn main() {
    let animal: Box<dyn Barks>;
    
    if 1 == 2 {
        animal = Box::new(Dog);
    } else {
        animal = Box::new(Wolf);
    }
    
    animal.bark();
}

Here, I’m allocating the Dog or Wolf on the heap, then casting that up to a Box<dyn Barks>. This is kind of like casting an object to an interface in something like C# or Java, or casting a Dog* to a Barks* in C++.

An entirely different approach you could also use would be enums. You could have enum Animal { Dog, Wolf } then define an impl Animal { fn bark(&self) { ... } }. Depends on whether you need a completely open-ended set of animals and/or multiple traits.

Finally, note that “kind of” above. There are various things that don’t work as they would in Java/C#/C++. For example, Rust doesn’t have downcasting (you can’t go from Box<dyn Barks> back to Box<Dog>, or from one trait to another). Also, this only works if the trait is “object safe” (no generics, no using self or Self by-value).

Leave a Comment