impl Trait
:静态分发
dyn Trait
:动态分发
静态分发:在编译期就确定了具体返回类型,函数只能返回一种类型。
动态分发:在运行时才能确定具体返回类型,函数可以返回多种类型。
Trait Object:指向trait的指针,假设Animal是一个triait,那么&Animal和Box<Animal>
都是一种Trait Object。
胖指针:用于指代动态大小类型(DST)的引用和原始指针(切片或特征对象)。胖指针包含一个指针以及一些使DST完成(例如长度)的信息。
返回值为impl Trait时用dyn Trait是没问题的
示例代码:
trait Animal {
fn get_kind(&self) -> String;
fn default_impl(&self) {
println!("default impl");
}
}
impl dyn Animal {
fn trait_object() {
println!("trait object");
}
}
#[derive(Debug)]
struct Dog {}
impl Animal for Dog {
fn get_kind(&self) -> String {
"Dog".to_string()
}
}
struct Cat {}
impl Animal for Cat {
fn get_kind(&self) -> String {
"Cat".to_string()
}
}
// 静态分发
fn get_animal_static() -> impl Animal {
let x = 1;
if x == 1 {
Dog {}
} else {
Dog {}
}
}
// 动态分发
fn get_animal_dyn() -> Box<dyn Animal> {
let x = 0;
if x == 1 {
Box::new(Dog {})
} else {
Box::new(Cat {})
}
}
fn main() {
let dog = Dog {};
dog.default_impl();
let cat = Cat {};
cat.default_impl();
// 只有 trait objects 才能调用
// dog.trait_object();
// cat.trait_object();
<dyn Animal>::trait_object();
let _ = &<dyn Animal>::trait_object();
let animal = get_animal_static();
// Dog
println!("{}", animal.get_kind());
let animal = get_animal_dyn();
// Cat
println!("{}", animal.get_kind());
}
参考:
胖指针:
https://www.sohu.com/a/475756949_121124378
impl Trait & dyn Trait
https://zhuanlan.zhihu.com/p/23791817
https://zhuanlan.zhihu.com/p/109990547