Devolver rasgos con dyn

The Rust compiler needs to know how much space every function's return type requires. This means all your functions have to return a concrete type. Unlike other languages, if you have a trait like Animal, you can't write a function that returns Animal, because its different implementations will need different amounts of memory.

El compilador de Rust necesita saber cuánto espacio requiere el tipo de retorno de cada función. Esto significa que todas sus funciones deben devolver un tipo concreto. A diferencia de otros lenguajes, si tienes un rasgo como Animal, no puedes escribir una función que devuelva Animal, porque sus diferentes implementaciones necesitarán diferentes cantidades de memoria.

Sin embargo, existe una solución sencilla. En lugar de devolver un objeto de rasgo directamente, nuestras funciones devuelven un Box que contiene partes de Animal. Una es solo una referencia a algo de memoria en el montón. Debido a que una referencia tiene un tamaño conocido estáticamente, y el compilador puede garantizar que apunta a un Animal asignado al montón, ¡podemos devolver un rasgo de nuestra función!

Rust intenta ser lo más explícito posible siempre que asigna memoria en el montículo. Entonces, si tu función devuelve un puntero a rasgo en el montículo de esta manera, debes escribir el tipo de retorno con la palabra clave dyn, por ejemplor Box<dyn Animal>.

struct Oveja {}
struct Vaca {}

trait Animal {
    // Signatura del método de instancia
    fn sonido(&self) -> &'static str;
}

// Implementa el rasgo `Animal` para `Oveja`.
impl Animal for Oveja {
    fn sonido(&self) -> &'static str {
        "baaaaah!"
    }
}

// Implementar el rasgo `Animal` para `Vaca`.
impl Animal for Vaca {
    fn sonido(&self) -> &'static str {
        "moooooo!"
    }
}

// Devuelve una estructura que implementa Animal, pero no sabemos cuál en tiempo de
// compilación.
fn animal_aleatorio(numero_aleatorio: f64) -> Box<dyn Animal> {
    if numero_aleatorio < 0.5 {
        Box::new(Oveja {})
    } else {
        Box::new(Vaca {})
    }
}

fn main() {
    let numero_aleatorio = 0.234;
    let animal = animal_aleatorio(numero_aleatorio);
    println!("Has elegido un animal al azar y dice {}", animal.sonido());
}