首页 > 其他分享 >rust_trait个人理解

rust_trait个人理解

时间:2023-09-16 15:33:11浏览次数:42  
标签:Draw 实例 特征 trait 对象 理解 类型 rust

0 概述

  1. 什么是trait

    rust中有许许多多的类型(枚举、结构体...),如果这些不同类型,都有类似的行为,我们把这个行为抽象出来,把他定义为一个特征(trait)

    一个trait中可以包含,一个或者一组行为,表现形式就是方法or函数

1 特征约束

1.1 特征约束

1.2 特征做函数参数的语法糖

真特么nb,看下面这个写法,这个意思就是所有实现了Summary特征的对象都能作为参数传递进去

fn main() {
	pub fn notify(item: &impl Summary) {
    	println!("Breaking news! {}", item.summarize());
	}
}

2 特征对象

实现了某个trait的实例,都被称为特征对象

比如我有weibo和post两个结构体,他们都实现了summary这个trait,那么他们俩的实例就是summary这个trait的特征对象

特征对象的这个映射关系,会存在一个表中,在运行时可以进行查询

可以通过 & 引用或者 Box<T> 智能指针的方式来创建特征对象

fn draw1(x: Box<dyn Draw>) {
    x.draw();
}

fn draw2(x: &dyn Draw) {
    x.draw();
}
  • draw1 函数的参数是 Box<dyn Draw> 形式的特征对象,该特征对象是通过 Box::new(x) 的方式创建的
  • draw2 函数的参数是 &dyn Draw 形式的特征对象,该特征对象是通过 &x 的方式创建的
  • dyn 关键字只用在特征对象的类型声明上,在创建时无需使用 dyn,dynamic

不知道你有没有发现,对于一个类型的设置,似乎有个dyn声明就能说明了,比如x:dyn draw。那么为什么rust要多次一举,写成智能指针形式?

原因是特征对象可以是任意实现了某个特征的类型,编译器在编译期不知道该类型的大小,不同的类型大小是不同的。

如果写成Box<dyn Draw>和&dyn Draw这时候的指针大小是确定的

一个特征对象的大小=两个指针(ptr+vptr)

总之,特征对象的两个指针们可以理解为一个 数据指针行为指针

3 rust静态分发和动态分发

静态分发:rust的泛型在编译时,会为每一个可能的泛型生成具体的代码,所以运行时几乎没有任何损耗,这个方式时静态分发

动态分发:特征对象是属于动态分发的。因为在编译的时候,编译器无法知道所有特征对象的具体类型,只能依靠指针来找具体类型

img

  • 一个指针 ptr 指向实现了特征 Draw 的具体类型的实例,也就是当作特征 Draw 来用的类型的实例,比如类型 Button 的实例、类型 SelectBox 的实例
  • 另一个指针 vptr 指向一个虚表 vtablevtable 中保存了类型 Button 或类型 SelectBox 的实例对于可以调用的实现于特征 Draw 的方法。当调用方法时,直接从 vtable 中找到方法并调用。之所以要使用一个 vtable 来保存各实例的方法,是因为实现了特征 Draw 的类型有多种,这些类型拥有的方法各不相同,当将这些类型的实例都当作特征 Draw 来使用时(此时,它们全都看作是特征 Draw 类型的实例),有必要区分这些实例各自有哪些方法可调用

注意

  1. 特征对象不同于实例对象,特征对象的vtable中只包含了实现Draw特征的方法

特征对象安全

不是所有的特征都能有特征对象,只有 对象安全的才有。

  1. 方法的返回类型不能是Self
  2. 方法不带任何的泛型参数

假设你有一个trait,trait中某个方法返回的是一个Self。当你在使用特征对象调用这个trait的方法时,你根本不知道这个特征对象的具体类型,你只知道他实现了这个trait,所以就不可能知道Self是什么了,同样你也不知道

3 关联类型

我个人感觉关联类型是用来替代在trait中的泛型参数的。你可以把这个泛型参数写成一个单独的关联类型

标签:Draw,实例,特征,trait,对象,理解,类型,rust
From: https://www.cnblogs.com/jye159X/p/17706791.html

相关文章

  • 深入理解Java中的反射机制
    什么是反射机制Java中的反射机制是指在运行时获取类的信息并操作类的属性、方法和构造函数等。通过反射机制,我们可以在运行时动态地创建对象、调用方法和访问属性等,而不需要在编译时确定这些信息。反射机制的应用场景反射机制在Java中有着广泛的应用场景,比如:动态代理动态代......
  • 如何理解DDD中的值对象
    引言实体和值对象是领域驱动设计中的两个重要概念。相对实体而言,值对象更加抽象,理解起来也更晦涩一些。那么该如何理解值对象?我们先来看一下《实现领域驱动设计》书中对值对象的定义:值对象(ValueObject)是通过对象属性值来识别的对象,它将多个相关属性组合成一个概念整体,用于......
  • 如何理解DDD中的值对象
    引言实体和值对象是领域驱动设计中的两个重要概念。相对实体而言,值对象更加抽象,理解起来也更晦涩一些。那么该如何理解值对象?我们先来看一下《实现领域驱动设计》书中对值对象的定义:值对象(ValueObject)是通过对象属性值来识别的对象,它将多个相关属性组合成一个概念整体,用于......
  • 深入理解Spring MVC框架及其工作原理
    SpringMVC是一种基于Java的Web应用程序开发框架,它提供了一种模型-视图-控制器(MVC)的架构模式,用于构建灵活、可扩展且高效的Web应用程序。本文将深入探讨SpringMVC框架的各个组件和工作原理。介绍SpringMVCSpringMVC是SpringFramework的一个模块,用于开发Web应用程序。它基于经......
  • 深入剖析模板引擎:理解原理、应用场景和常见类型
    模板引擎是一种广泛应用于Web开发的工具,能够将动态数据与静态模板进行结合,生成最终的页面内容。本篇博客将详细介绍模板引擎的原理、常见应用场景以及多种类型的模板引擎。引言模板引擎是现代Web开发中不可或缺的一部分,它的作用是将静态的模板文件与动态的数据进行结合,生成最终呈......
  • Rust 开发命令行工具(上)
    ❝你必须按所想去生活,否则只能按生活去想。--王小波❞大家好,我是「柒八九」。作为一个前端/Rust/AI知识博主,之前的文章中,大部分篇幅都是关于前端的知识分享,而对Rust和AI的内容只是做了几篇内容梳理和介绍。而,我们今后的重心也会逐渐偏移,势必能达到前端/Rust/AI「三足鼎立」的局面......
  • SQL Server关于AlwaysOn的理解-读写分离的误区(一)
       很多人认为AlwaysOn在同步提交模式下数据是实时同步的,也就是说在主副本写入数据后可以在辅助副本立即查询到。因此期望实现一个彻底的读写分离策略,即所有的写语句在主副本上,所有的只读语句分离到辅助副本上。这是一个认知误区,本文通过原理和测试进行解释。实现原理从下图可......
  • android中的VERSION和VERSION_CODES和compileSdkVersion, minSdkVersion 和 targetSdk
    一背景经常会有代码中用到  Build.VERSION.SDK_INT<Build.VERSION_CODES.O,这是指什么意思。在app项目中,经常会看到android{compileSdkVersion30buildToolsVersion"30.0.3"defaultConfig{applicationId"com.yl.qrcode"minSdkVersio......
  • CN0+CN1+CN2+…+CNN = 2的N次方 如何理解?
    关于标题所示的经典公式的理解数学角度讲是二项式定理,证明过程不记得了但是这个回答里看到一个非常有意思的思路,从程序员角度比较好接受参考链接知乎:CN0+CN1+CN2+…+CNN如何得出等于2的N次方?PS疑问来源:《算法图解:第8章贪婪算法》8.3集合覆盖问题一节中提到,要找出覆盖......
  • Spring面试攻略:如何展现你对Spring的深入理解
    什么是Spring?谈谈你对IOC和AOP的理解。Spring是一种Java开发框架,旨在简化企业级应用程序的开发和部署。它具有以下优点:对象托管:Spring能够管理和赋值所有对象,使开发人员不再需要手动管理对象的创建和依赖关系。动态代理:Spring的动态代理功能可以实现大部分可复用的逻辑功能,从而......