使用 dyn 返回 Trait

Rust 编译器需要知道每个函数的返回类型需要多少空间。这意味着你所有的函数都必须返回一个具体的类型。与其他语言不同,如果你有一个像 Animal 这样的 trait,你不能编写一个返回 Animal 的函数,因为它的不同实现需要不同大小的内存。

但是,有一个简单的解决方法。我们的函数不是直接返回 trait 对象,而是返回一个 Box,它*包含*一些 AnimalBox 只是一个指向堆内存的引用。因为引用具有静态已知的大小,并且编译器可以保证它指向堆分配的 Animal,所以我们可以从我们的函数返回一个 trait!

当 Rust 在堆上分配内存时,它会尽可能地明确。所以如果你的函数以这种方式返回一个指向堆上 trait 的指针,你需要使用 dyn 关键字来编写返回类型,例如 Box<dyn Animal>

struct Sheep {}
struct Cow {}

trait Animal {
    // Instance method signature
    fn noise(&self) -> &'static str;
}

// Implement the `Animal` trait for `Sheep`.
impl Animal for Sheep {
    fn noise(&self) -> &'static str {
        "baaaaah!"
    }
}

// Implement the `Animal` trait for `Cow`.
impl Animal for Cow {
    fn noise(&self) -> &'static str {
        "moooooo!"
    }
}

// Returns some struct that implements Animal, but we don't know which one at compile time.
fn random_animal(random_number: f64) -> Box<dyn Animal> {
    if random_number < 0.5 {
        Box::new(Sheep {})
    } else {
        Box::new(Cow {})
    }
}

fn main() {
    let random_number = 0.234;
    let animal = random_animal(random_number);
    println!("You've randomly chosen an animal, and it says {}", animal.noise());
}