Rust學(xué)習(xí)——trait對(duì)象

一、靜態(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ā)
思路:

  1. 關(guān)鍵在于,當(dāng)將trait impl到 對(duì)象之后,對(duì)象中重寫的trait方法,會(huì)在虛函數(shù)表中存儲(chǔ)該方法,
  2. 當(dāng)通過(guò)(&對(duì)象 as &trait)后,便實(shí)現(xiàn)了指針連接,即將traitObject(胖指針)的一個(gè)指針指向?qū)ο?,再將另一個(gè)指針指向一個(gè)虛函數(shù)表,
  3. 其中虛函數(shù)表中含有,在impl trait for 對(duì)象 時(shí)重寫的方法地址和虛表的偏移量,將虛表地址和偏移量結(jié)合可以確認(rèn)該對(duì)象所從寫的trait方法
  4. 當(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
    // };
}```
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容