当前位置: 首页 > article >正文

Rust中的静态派发与动态派发

Rust中的静态派发与动态派发

  • 前言
  • Dynamically Sized Types
    • 指向切片和特征对象的指针与其他的有什么区别
  • 特征约束的代码实现
  • 特征对象动态派发代码实现
  • 什么时候只能用动态派发


前言

在CPP语言中,为了代码的灵活性和复用性,模板和继承中的父类指针指向子类引用的实现方式被开发者喜欢,对于Rust来说,便是泛型,特征约束和dyn关键字。他们的目的类似,只不过在特定的语言范围内使用方式不大相同。在rust泛型与特征一文中,我们讨论了Box< dyn Trait >的写法,本文做进一步的补充说明,这里关注于代码举例与细节对比


Dynamically Sized Types

一般实现了trait Sized的类型在编译期就知道他们的大小,而对于在runtime期间在可以知道他们的真实大小的类型就是DST。而对于Rust编译期来说,安全是非常重要的,每一种类型在编译期都需要知道Sized才能进入编译否则报错,不论你是变量、函数参数,还是其他的什么。那么对于本章讨论的动态派发中的特征对象,也逃不过这样的限制,开发者有两种选择,或是使用&引用,或是使用Box智能指针。

指向切片和特征对象的指针与其他的有什么区别

其最大的区别就是,指向切片的指针同时保存了切片中包含数据的数量,指向特征对象的指针,一个指向了自己的特定类型,同时保留了一个虚表指针用于指向虚表,所以这两种指针是普通指针的两倍大小,从而在runtime期间可以精准的让特定的类型调用到特定的方法(虚表已经在泛型与特征一文中有所表述,这里不再赘述)

特征约束的代码实现

trait Sound {
    fn make_sound(&self);
}

struct Cat;

impl Sound for Cat {
    fn make_sound(&self) {
        println!("Meow!");
    }
}

struct Dog;

impl Sound for Dog {
    fn make_sound(&self) {
        println!("Woof!");
    }
}

fn make_sound<Animal: Sound>(a: &Animal) {
    a.make_sound();
}

fn main() {
    let dog = Dog;
    let cat = Cat;
    make_sound(&dog);
    make_sound(&cat);
}

特征对象动态派发代码实现

trait Sound {
    fn make_sound(&self);
}

struct Cat;

impl Sound for Cat {
    fn make_sound(&self) {
        println!("Meow!");
    }
}

struct Dog;

impl Sound for Dog {
    fn make_sound(&self) {
        println!("Woof!");
    }
}

fn make_sound(animal: &dyn Sound) {
    animal.make_sound();
}

fn main() {
    let dog = Dog;
    let cat = Cat;
    make_sound(&dog);
    make_sound(&cat);
}

什么时候只能用动态派发

当方法内部需要返回不同类型的时候,如下:

fn something(xx)->impl Sound{
	if {
		return Dog;
	}else{
		return Cat;
	}
}

这样的是不成立的,大多数文章会写因为类型需要在编译期确定,这看起来似乎是解释了原因,那么在这里多问一句,这怎么就不是编译期确定的类型呢?因为返回值类型有两个,编译器无法像函数调用一样,通过参数的不同(Dog or Cat),从而在编译期间确定参数类型是什么,而使用特征约束的,只能确定一个类型,要么Dog要么Cat,都有的话,编译期会认为一个值有两种类型从而报错。

正确的使用方法如下:

fn something(xx)->Box<dyn Sound>{
	if {
		return Box::from(Dog);
	}else{
		return Box::from(Cat);
	}
}

http://www.kler.cn/a/407453.html

相关文章:

  • Javaweb前端HTML css 整体布局
  • DevOps-Jenkins-新手入门级
  • Web 入门
  • 深度学习3
  • Redis的特性ubuntu进行安装
  • 136.flask内置jinja2模版使用
  • 数据结构--跳表
  • Spark 中的 Shuffle 是分布式数据交换的核心流程,从源码角度分析 Shuffle 的执行路径
  • Microsoft SEAL中dwthandler.h解析
  • OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用
  • 【Python · PyTorch】循环神经网络 RNN(基础概念)
  • Rust 力扣 - 198. 打家劫舍
  • 【汽车制动】汽车制动相关控制系统
  • UE5材质篇5 简易水面
  • 11-23刷题记录
  • 23、论文阅读:基于多分辨率特征学习的层次注意力聚合GAN水下图像增强
  • Docker 实践与应用举例:提升开发与运维效率的利器
  • 阿里Qwen系列开源模型介绍
  • 设计模式之 原型模式
  • 高危,Laravel参数注入漏洞安全风险通告
  • 神经网络(系统性学习一):入门篇——简介、发展历程、应用领域、基本概念、超参数调优、网络类型分类
  • SQL的四种语言介绍
  • JavaWeb之综合案例
  • 笔记整理—linux驱动开发部分(15)BMP图片显示
  • 微软安全文章合集
  • Redis进阶Redission实现分布式锁