struct Sheep {} struct Cow {} trait Animal { fn noise(&self) -> String; } impl Animal for Sheep { fn noise(&self) -> String { "baaaaah!".to_string() } } impl Animal for Cow { fn noise(&self) -> String { "moooooo!".to_string() } } // 返回一个类型,该类型实现了 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.7; let animal = random_animal(random_number); println!("You've randomly chosen an animal, and it says {}", animal.noise()); }
trait作为DST, 是无法在编译期间确定大小的,如果想通过静态派发来实现,泛型是一种选择, 或者impl Trait也可以达成。如果通过动态派发来实现的话,那我们就需要用box dyn。 在编写过程中,类型信息被故意的隐去了,就留下了一个dyn trait,具体是针对哪个版本类型的调用,被延迟到了运行时,在对应trait的vtable的指针上。dyn trait,本质上也是一个DST, 对应的,我们就可以用&dyn trait, &mut dyn trait, Box<dyn trait>.... 和定义,操作其他类型一样,操作这个类型。指向trait的pointer,也是一个fat pointer,里面除了指向的对象本身,还有个vtable的地址信息,在这里的vtable就是对应的方法实现的函数入口。