Rust的运行时多态

Rust的运行时多态

Rust的静态多态即编译时多态,通过**泛型+特征约束(Generic Type + Trait Constrait)**来实现;

那么动态多态(运行时多态)呢?答案是特征对象(Trait Object)

特征对象不是一个实例,而是一个结构体类型。

语法是dyn TraitName,编译时指示某个对象是实现TraitName的类型,其具体类型未知。

分析

程序运行时,要调用一个特征方法,需要两个要素:

  • 对象实例(对象类型未知,因此其编译期大小未知)
  • 特征的方法表

所以特征对象结构体必须获知以上两个要素。

发生运行时多态时,在编译阶段编译器无法辨别对象实例的类型,因此对象实例要素的大小无法获知,进而特征对象(Trait Object)的大小在编译阶段无法被确定,这决定了Trait Object只能存放在堆上,通过引用或智能指针来访问

指向特征对象的引用或智能指针,包含了两个指针成员,在程序运行时,ptr1在指向对象实例,ptr2指向该对象类型的Trait Method实现。

典型用例

rust 复制代码
#[derive(Debug)]
struct Journal {
    author: String,
    year: u16,
    from: String,
}
#[derive(Debug)]
struct Conference {
    author: String,
    year: u16,
    country: String,
}

trait Summary {
    fn summary(&self) -> String;
}

impl std::fmt::Debug for dyn Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.summary())
    }
}

impl Summary for Journal {
    fn summary(&self) -> String {
        format!("{}\t{}\t{}", self.author, self.year, self.from)
    }
}
impl Summary for Conference {
    fn summary(&self) -> String {
        format!("{}\t{}\t{}", self.author, self.year, self.country)
    }
}

// can't defer concrete type in compile stage, trait constrain can't used here
// fn init_default(_type: &str) -> impl Summary {
//     if _type == "journal" {
//         Journal {
//             author: "hjd".to_owned(),
//             year: 2018,
//             from: "Nature".to_owned(),
//         }
//     } else {
//         Conference {
//             author: "hjd".to_owned(),
//             year: 2018,
//             country: "China".to_owned(),
//         }
//     }
// }

// 只能使用特征对象进行动态分发,因为返回类型编译期无法推理获知
fn init_default(_type: &str) -> Box<dyn Summary> {
    if _type == "journal" {
        Box::new(Journal {
            author: "hjd".to_owned(),
            year: 2018,
            from: "Nature".to_owned(),
        })
    } else {
        Box::new(Conference {
            author: "hjd".to_owned(),
            year: 2018,
            country: "China".to_owned(),
        })
    }
}

fn main() {
    let p1 = init_default("journal");
    let p2 = init_default("conference");
    let p3 = init_default("journal");
    let p4 = init_default("conference");

    let p_list = vec![p1, p2, p3, p4];
    // dyn Summary是一个特征对象类型,它忘记了自己之前的具体类型,只能调用Summary特征中的方法
    for p in p_list.iter() {
        println!("{:?}", p);
    }
}
相关推荐
好大哥呀10 小时前
Java 中的 Spring 框架
java·开发语言·spring
hhzz10 小时前
Springboot项目中使用EasyPOI操作Excel(详细教程系列4/4)
java·spring boot·后端·spring·excel·poi·easypoi
charlie11451419110 小时前
输入法处理杂谈——Windows 下的 IMM32 输入法处理机制和Chrome如何桥接TSF输入法
开发语言·chrome·windows·学习·输入法
froginwe1110 小时前
Ruby Dir 类和方法
开发语言
代码游侠10 小时前
学习笔记——ARM Cortex-A 裸机开发实战指南
linux·运维·开发语言·前端·arm开发·笔记
星火开发设计10 小时前
表达式与语句:C++ 程序的执行逻辑基础
java·开发语言·c++·学习·知识·表达式
纵有疾風起10 小时前
【Linux 系统开发】基础开发工具详解:软件包管理器、编辑器。编译器开发实战
linux·服务器·开发语言·经验分享·bash·shell
郝学胜-神的一滴10 小时前
Qt与Web混合编程:CEF与QCefView深度解析
开发语言·前端·javascript·c++·qt·程序人生·软件构建
冬奇Lab10 小时前
【Kotlin系列08】泛型进阶:从型变到具体化类型参数的类型安全之旅
android·开发语言·windows·安全·kotlin
fareast_mzh10 小时前
Why Web2 → Web3 is slow
开发语言·web3