使用 dyn 返回特征

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

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

每当在堆上分配内存时,Rust 都会尽量做到显式。因此,如果你的函数以这种方式返回指向堆上特征的指针,则需要使用 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());
}