Rust 多态

分发

多态的上下文中的方法解析过程被称为分发,调用该方法称为分发化,在支持多态的主流语言中,分发可以通过以下任意一种方式进行。

静态分发

当在编译期决定要调用的方法时,它被称为静态分发或早期绑定。

Rust中的泛型属于静态分发,因为即使泛型函数可以接收多种类型参数,但是在编译时会生成特定类型的专用副本。

动态分发

直到运行时才能确定调用的方法,被称为动态分发。这是因为具体类型被隐藏,只能通过接口实例调用。

在动态分发过程中,可以通过对vtable(虚表)接口的实现列表进行查找,并调用该方法来动态确定相关方法。vtable是一个在固定偏移处为每个对象的方法保留一个函数指针的结构体。

特征对象(trait object)

特征对象是Rust执行动态分发的方式,它被实现为胖指针,并且是不定长类型,这意味着它们只能在引用符号(&)后面使用。特征对象胖指针具有指向与对象关联的实际数据的第一指针和指向vtable的第二指针。在运行时,我们没有实际类型的具体信息,只能通过trait的信息在vtable中找到适当的方法并调用。

trait object实现多态:

use std::fmt::Debug;
#[derive(Debug)]
struct Square(f32);
#[derive(Debug)]
struct Rectangle(f32,f32);
trait Area:Debug {
fn get_area(&self)->f32;
}
impl Area for Square {
fn get_area(&self)->f32 {
self.0*self.0
}
}
impl Area for Rectangle {
fn get_area(&self)->f32 {
self.0*self.1
}
}
fn main() {
let s:&dyn Area=&Square(3f32);
println!("{:?}",s.get_area());
let rec:&dyn Area=&Rectangle(4f32,2f32);
println!("{:?}",rec.get_area());
}

特征对象的一个用例是在一个集合中存储多种不同类型但具有共同trait的实例:

use std::fmt::Debug;
#[derive(Debug)]
struct Square(f32);
#[derive(Debug)]
struct Rectangle(f32,f32);
trait Area:Debug {
fn get_area(&self)->f32;
}
impl Area for Square {
fn get_area(&self)->f32 {
self.0*self.0
}
}
impl Area for Rectangle {
fn get_area(&self)->f32 {
self.0*self.1
}
}
fn main() {
let shapes:Vec<&dyn Area>=vec![&Square(3f32),&Rectangle(4f32,2f32)];
for e in shapes{
println!("{:?}",e.get_area());
}
}

注意:上述实例将Square和Rectangle的构造为特征对象,由于我们不知道实际类型的大小,所以dyn Trait是一个不定长类型,只能作为引用使用。或者将其置于特征其他智能指针之后:

 	let s:Box<dyn Area>=Box::new(Square(3f32));
println!("{:?}",s.get_area());
let rec:Box<dyn Area>=Box::new(Rectangle(4f32,2f32));
println!("{:?}",rec.get_area());
let shapes:Vec<Box<dyn Area>>=vec![Box::new(Square(3f32)),Box::new(Rectangle(4f32,2f32))];
for e in shapes{
println!("{:?}",e.get_area());
}

还可以将dyn Trait作为函数参数,以接收不同实际类型的实例参数:

fn get_area(item:&dyn Area)->f32{
item.get_area()
}
fn main() {
let shapes:Vec<&dyn Area>=vec![&Square(3f32),&Rectangle(4f32,2f32)];
for e in shapes{
println!("{:?}",get_area(e));
}
}

最新文章

  1. Spring获取ApplicationContext
  2. embed chrome 无法播放问题
  3. Centos配置查看
  4. iOS开发小技巧--实现将图片保存到本地相册
  5. android TextView加载html内容并加载图片
  6. iOS类别(category)不能添加成员变量但是可以添加属性的问题
  7. Matlab read_grib.r4 安装新方法(转自:http://blog.sina.com.cn/s/blog_9f36648b010179s7.html)
  8. QWidget与HWND的互相转换
  9. react服务端渲染(同构)
  10. jQuery中on()方法用法实例详解
  11. 采用ACE登录设施(一)HelloWorld
  12. php安装详解
  13. httpClient 发送请求后解析流重用的问题(HttpEntity的重用:BufferedHttpEntity)
  14. nova创建虚拟机源码系列分析之二 wsgi模型
  15. Nginx 在线新增模块
  16. springboot使用fastjson中文乱码解决方法 【转载】
  17. 零基础IDEA整合SpringBoot + Mybatis项目,及常见问题详细解答
  18. 微信web开发者工具 移动调试
  19. 全网最详细的Eclipse里如何正确新建普通的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(图文详解)
  20. Lodop客户端本地角色注册号常见误区

热门文章

  1. django+x-admin管理后台模板开发管理后台案例(设计部分)
  2. 《RT-Thread Studio开发STM32》第一章~第一节《配置STM32H743XIH6点亮LED灯》
  3. Lua OpenResty容器化(考古历程)
  4. 由孙悟空的七十二变看Java设计模式:装饰者模式
  5. HACK TEH BOX - Under Construction(JWT密钥混淆 + SQL注入)
  6. 002-Java的标识符和关键字
  7. Digit Generator UVA - 1583
  8. ASP.NET CORE使用WebUploader对大文件分片上传,并通过ASP.NET CORE SignalR实时反馈后台处理进度给前端展示
  9. Tomcat配置及网站创建教程(IDEA)
  10. Mybatis的简单增删改查