一、靜態(tài)分發(fā):依靠泛型支持,實(shí)際上為通過(guò)編譯期將泛型類型擴(kuò)展為實(shí)際類型,實(shí)現(xiàn)單態(tài),最后的結(jié)果是代碼量的膨脹。
trait Foo {
fn method(&self) -> String;
}
impl Foo for u8 {
fn method(&self) -> String { format!("u8: {}", *self) }
}
impl Foo for String {
fn method(&self) -> String { format!("string: {}", *self) }
}
fn do_something<T: Foo>(x: T) {
x.method();
}
fn main() {
let x = 5u8;
let y = "Hello".to_string();
do_something(x);
do_something(y);
}
//-----------------------------------------------------------------------------------------
// 在編譯期,編譯期會(huì)將泛型翻譯為實(shí)際類型,針對(duì)具體類型分別實(shí)現(xiàn)函數(shù),調(diào)用的時(shí)候調(diào)用的是各自的函數(shù),如下
fn do_something_u8(x: u8) {
x.method();
}
fn do_something_string(x: String) {
x.method();
}
fn main() {
let x = 5u8;
let y = "Hello".to_string();
do_something_u8(x);
do_something_string(y);
}
二、動(dòng)態(tài)分發(fā):利用對(duì)象指針和函數(shù)指針的組合實(shí)現(xiàn)運(yùn)行期的多類型分發(fā)
思路:
- 關(guān)鍵在于,當(dāng)將trait impl到 對(duì)象之后,對(duì)象中重寫的trait方法,會(huì)在虛函數(shù)表中存儲(chǔ)該方法,
- 當(dāng)通過(guò)(&對(duì)象 as &trait)后,便實(shí)現(xiàn)了指針連接,即將traitObject(胖指針)的一個(gè)指針指向?qū)ο?,再將另一個(gè)指針指向一個(gè)虛函數(shù)表,
- 其中虛函數(shù)表中含有,在impl trait for 對(duì)象 時(shí)重寫的方法地址和虛表的偏移量,將虛表地址和偏移量結(jié)合可以確認(rèn)該對(duì)象所從寫的trait方法
- 當(dāng)調(diào)用該方法時(shí),通過(guò)這個(gè)指針獲取實(shí)際對(duì)象以及該實(shí)際對(duì)象重寫的trait方法。
// 定義trait及方法
trait Bird {
fn fly(&self);
}
struct Duck;
struct Swan;
// 將trait impl到 Duck中,將重寫的trait方法存入虛函數(shù)表
impl Bird for Duck {
fn fly(&self){
println!("duck duck");
}
}
// 將trait impl到 Swan中,將重寫的trait方法存入虛函數(shù)表
impl Bird for Swan {
fn fly(&self){
println!("Swan Swan");
}
}
// 定義一個(gè)調(diào)用函數(shù)
// fn print_trait_obj(p: &dyn Bird){
// p.fly();
// }
fn main() {
// 新建對(duì)象
let duck = Duck;
// 創(chuàng)建 對(duì)象的引用
let p_duck = &duck;
// 將對(duì)象引用 轉(zhuǎn)換成 trait對(duì)象,這個(gè)過(guò)程中——trait對(duì)象為胖指針(指針1.p_duck;指針2.(虛函數(shù)表+Duck的trait方法在虛函數(shù)表中的偏移量))
let p_bird = p_duck as &dyn Bird;
// 當(dāng)調(diào)用trait方法時(shí),從指針1中獲取對(duì)象,從指針2中獲取trait方法
// print_trait_obj(p_bird);
p_bird.fly(); // 因?yàn)閒ly(&self), 所以等價(jià)于 (p_bird.vtable.fly)(p_duck)
// 同理
let swan = Swan;
let p_swan = &swan;
let p_bird = p_swan as &dyn Bird; // 指針p_bird發(fā)生了重綁定
p_bird.fly();
// y 為struct
// let y = TraitObject {
//data存儲(chǔ)實(shí)際值的引用
// data: &x,
// vtable存儲(chǔ)實(shí)際類型實(shí)現(xiàn)Foo的方法
// vtable: &Foo_for_u8_vtable
// };
}```