Traits as a return value from a function [duplicat

2019-01-20 08:25发布

问题:

This question already has an answer here:

  • How do I return an instance of a trait from a method? 3 answers

I have two enums, NormalColour and BoldColour, both of which implement the Colour trait. They contain Blue, BoldGreen, and so on.

I'd like to return values of both of these types from the same function, treating them as though they're just a Colour value, calling the paint function on the result, but I can't find a way to coerce the Rust complier into doing this for me. I'd like to be able to write something like this:

pub trait Colour {
    fn paint(&self, input: &str) -> String;
}

fn file_colour(stat: &io::FileStat) -> Colour {
    if stat.kind == io::TypeDirectory {
        Blue
    } else if stat.perm & io::UserExecute == io::UserExecute {
        BoldGreen
    } else {
        White
    }
}

What type do I have to make the function return for it to work?

I'll eventually like to make more types implement Colour, which is why I'm not interested in just turning the two enums into one big enum.

回答1:

The answer is trait objects. This means that you will work with Box<Colour> as your type; bare Colour is not an instantiable type. You can cast Box<T> objects to Box<Colour> with the as operator: Box::new(NormalColour::White) as Box<Colour>. In many places this is not necessary (just write Box::new(NormalColour::White) and it can be automatically coerced to Box<Colour>), but sometimes it will still be necessary.

Still, if you can do it as an enum, that will probably be a nicer solution.



回答2:

The answer above suggests:

fn file_colour(stat: &io::FileStat) -> Box<Colour> { /* ... */ }

which works, but you need to wrap all of the returns in a Box::new() call.

However, in Rust 1.26 you can now say

fn file_colour(stat: &io::FileStat) -> impl Colour { /* ... */ }

and simply return the value. No Box needed.



标签: traits rust