使用 dyn 返回 trait

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

然而,有一个简单的解决方法。我们可以让函数返回一个包含 AnimalBox,而不是直接返回 trait 对象。Box 本质上是一个指向堆内存的引用。由于引用的大小是静态已知的,且编译器可以保证它指向堆上分配的 Animal,这样我们就能从函数中返回一个 trait 了!

Rust 在堆上分配内存时力求明确。因此,如果你的函数以这种方式返回一个指向堆上 trait 的指针,你需要在返回类型中使用 dyn 关键字,例如 Box<dyn Animal>

struct Sheep {}
struct Cow {}

trait Animal {
    // 实例方法签名
    fn noise(&self) -> &'static str;
}

// 为 `Sheep` 实现 `Animal` trait
impl Animal for Sheep {
    fn noise(&self) -> &'static str {
        "咩~!"
    }
}

// 为 `Cow` 实现 `Animal` trait
impl Animal for Cow {
    fn noise(&self) -> &'static str {
        "哞~哞~哞~"
    }
}

// 返回某个实现了 Animal 的结构体,但在编译时我们并不知道具体是哪一个
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!("你随机选择了一个动物,它说:{}", animal.noise());
}