美文网首页
Rust学习——trait对象

Rust学习——trait对象

作者: P2501 | 来源:发表于2020-12-22 14:49 被阅读0次

一、静态分发:依靠泛型支持,实际上为通过编译期将泛型类型扩展为实际类型,实现单态,最后的结果是代码量的膨胀。

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);
}
//-----------------------------------------------------------------------------------------
// 在编译期,编译期会将泛型翻译为实际类型,针对具体类型分别实现函数,调用的时候调用的是各自的函数,如下
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);
}

二、动态分发:利用对象指针和函数指针的组合实现运行期的多类型分发
思路:

  1. 关键在于,当将trait impl到 对象之后,对象中重写的trait方法,会在虚函数表中存储该方法,
  2. 当通过(&对象 as &trait)后,便实现了指针连接,即将traitObject(胖指针)的一个指针指向对象,再将另一个指针指向一个虚函数表,
  3. 其中虚函数表中含有,在impl trait for 对象 时重写的方法地址和虚表的偏移量,将虚表地址和偏移量结合可以确认该对象所从写的trait方法
  4. 当调用该方法时,通过这个指针获取实际对象以及该实际对象重写的trait方法。
// 定义trait及方法
trait Bird {
    fn fly(&self);
}

struct Duck;
struct Swan;

// 将trait impl到 Duck中,将重写的trait方法存入虚函数表
impl Bird for Duck {
    fn fly(&self){
        println!("duck duck");
    }
}

// 将trait impl到 Swan中,将重写的trait方法存入虚函数表
impl Bird for Swan {
    fn fly(&self){
        println!("Swan Swan");
    }
}

// 定义一个调用函数
// fn print_trait_obj(p: &dyn Bird){
//     p.fly();
// }

fn main() {
    // 新建对象
    let duck = Duck;

    // 创建 对象的引用
    let p_duck = &duck;

    // 将对象引用 转换成 trait对象,这个过程中——trait对象为胖指针(指针1.p_duck;指针2.(虚函数表+Duck的trait方法在虚函数表中的偏移量))
    let p_bird = p_duck as &dyn Bird;

    // 当调用trait方法时,从指针1中获取对象,从指针2中获取trait方法
    // print_trait_obj(p_bird);
    p_bird.fly();  // 因为fly(&self), 所以等价于 (p_bird.vtable.fly)(p_duck)

    // 同理
    let swan = Swan;
    let p_swan = &swan;
    let p_bird = p_swan as &dyn Bird;  // 指针p_bird发生了重绑定
    p_bird.fly();

    // y 为struct
    // let y = TraitObject {
            //data存储实际值的引用
    //     data: &x,
            // vtable存储实际类型实现Foo的方法
    //     vtable: &Foo_for_u8_vtable
    // };
}```

相关文章

  • Rust学习——trait对象

    一、静态分发:依靠泛型支持,实际上为通过编译期将泛型类型扩展为实际类型,实现单态,最后的结果是代码量的膨胀。 二、...

  • Rust学习───trait

    什么是trait?如果了解Java语言的话,你就可以把trait理解为Java的interface接口 定义pub...

  • rust Iterator

    Rust Iterator设计: 定义: 对Iterator Trait的理解: Rust的Iterator在大部...

  • [Rust]Trait

    trait定义了某一个类型所具有的特定行为,跟Java中的抽象类有类似,但有一些区别。trait中可以包含常量,函...

  • Rust Trait

    观感 Rust的Trait和Golang的interface看起来非常相似,从开发者角度来看,都可以实现具体类型的...

  • Rust for cpp dev - 使用 Trait 对象实现

    假设我们希望设计一个 GUI 库,对于每一个组件,我们希望能调用 draw() 方法来显示。 对于传统的有“继承”...

  • Rust impl trait

    trait特性 trait特性可以理解为Java中的接口,具备和接口很类似的特性。trait中的函数叫做方法。某个...

  • rust-trait

    什么是trait,trait相对于java就是interface。 基本的trait例子 在trait中,由sel...

  • Rust 闭包学习 (Fn/FnMut/FnOnce)

    学习 Rust 闭包记录 闭包作为参数 闭包作为结构体属性 异步使用闭包 主要就是加 Send trait,没加 ...

  • 【RUST_BASIC】Rust 高级 trait

    1 关联类型 关联类型(associated types)是一个将类型占位符与 trait 相关联的方式,这样 t...

网友评论

      本文标题:Rust学习——trait对象

      本文链接:https://www.haomeiwen.com/subject/hfxsnktx.html