【Rust自学】10.3. trait Pt.1:trait的定义、约束与实现
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
题外话:trait的概念非常非常非常重要!!!整个第10章全都是Rust的重难点!!!

10.3.1. 什么是trait
trait意为特征、特质。trait用来向Rust编译器描述某种类型具有哪些并且可以与其它类型共享的功能。trait可以以抽象的方式来定义共享的行为。
与trait相关的还有trait bounds(约束)的概念,它可以将泛型类型参数指定为实现了特定行为的类型。换句话说就是要求泛型的类型参数实现了某些triat。
Rust里的trait与其他语言的接口(interface)有点类似,但还是有区别的。
10.3.2. 定义一个trait
类型的行为由该类型本身可调用的方法来组成。有时候在不同的类型上都具有相同的方法,这时候就称这些类型共享了相同的行为。trait提供了一种方式可以把一些方法放到一起,从而定义实现某种目的所必需的一种行为。
- 定义trait使用关键字
trait,在trait的定义内只有方法签名,没有具体实现 - trait可以有多个方法,每个方法占一行,以
;结尾 - 实现该trait的类型必须提供具体的方法实现,也就是必须有方法体
看个例子:
pub trait Summary {fn summarize(&self) -> String;
}
trait前面加上pub代表公共的,这个trait的名字是Summary,里面有一个方法的签名叫summerize,除了&self之外没有其他参数,返回类型是String,然后加一个;就结束了这个签名,它没有方法体,也就是没有具体的实现。当然一个trait下可以有很多个方法签名:
pub trait Summary {fn summarize(&self) -> String;fn summarize1(&self) -> String;fn summarize2(&self) -> String;//......
}
10.3.3. 在类型上实现trait
在类型上实现trait与为类型实现方法很类似,但是也有不同之处。
为类型实现方法的写法是impl关键字后面跟着类型就可以了:
impl Yyyy {....}
而在类型上实现trait的写法是:
impl Xxxx for Yyyy {....}
Xxxx指的是trait的名Yyyy指的是类型的名- 在花括号内需要对trait里的方法签名写下具体的实现
看个例子(lib.rs):
pub trait Summary {fn summarize(&self) -> String;
}pub struct NewsArticle {pub headline: String,pub location: String,pub author: String,pub content: String,
}impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{}, by {} ({})", self.headline, self.author, self.location)}
}pub struct Tweet {pub username: String,pub content: String,pub reply: bool,pub retweet: bool,
}impl Summary for Tweet {fn summarize(&self) -> String {format!("{}: {}", self.username, self.content)}
}
- 结构体
NewsArticle表示新闻文章,它有4个字段:headline标题、location地点、author作者、content内容 - 结构体
Tweet表示推特(现在是X了)推文,它有四个字段:username用户名、content内容、reply是否有回复、retweet是否是转发
这两个结构体类型肯定不同,里面的字段大部分也不同。但是它们都可以有一个同样的行为——提取摘要Summary,所以就分别在这两个类型上实现Summary这个trait。
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{}, by {} ({})", self.headline, self.author, self.location)}
}
这一段是在NewsArticle实现trait,因为在定义trait时写了summarize的方法签名,所以在这里就得写具体的实现:使用format!这个宏将self.headline、self.author和self.location组成一个字符串返回。
impl Summary for Tweet {fn summarize(&self) -> String {format!("{}: {}", self.username, self.content)}
}
这一段是在Tweet上实现trait,也是一样的写summarize的具体实现:使用format!这个宏将self.username和self.content组成一个字符串返回。
然后来到main.rs,看它们实例的调用:
use RustStudy::{Summary, Tweet};fn main() {let tweet = Tweet {username: String::from("horse_ebooks"),content: String::from("of course, as you probably already know, people",),reply: false,retweet: false,};println!("1 new tweet: {}", tweet.summarize());
}
记住在main函数里使用之前要先引入作用域,写法是:
use 你的package名::...::你需要的模块
你的package名就是Cargo.toml里的项目名,把它复制下来即可
这里引入Summary是因为使用了在Summary这个trait下的summarize方法;引入Tweet是因为使用了Tweet这个结构体。
看一下输出:
1 new tweet: horse_ebooks: of course, as you probably already know, people
10.3.4. trait的约束
想要在某个类型上实现某个trait的前提条件是:
- 这个类型(比如说
Tweet类型)或这个trait(让Vector实现本地的Summary)是在本地crate里定义的 - 无法为外部类型实现外部trait。比如说在本地库里为标准库的
Vector实现标准库的Displaytrait。
这个限制是程序属性的一部分(也就是一致性)。更具体的说是孤儿原则,之所以这么命名是因为它的父类型并没有定义在当前库中。这个规则确保了其他人的代码不能随意破坏你的代码,反之亦然。如果没有这个规则,两个crate可以为同一个类型实现同一个trait,Rust就不知道应该使用哪个实现。
10.3.5. 默认实现
有些时候,为trait中的某些或者是所有方法提供默认行为是非常有用的,它可以使我们无需为每一个类型的实现都提供自定义的行为。我们可以针对某些特定的类型实现trait里的方法。
当我们为某些类型实现trait时,我们可以选择保留或是重载每个方法的默认实现。
之前的写法是:
pub trait Summary {fn summarize(&self) -> String;
}
之前的写法只写了方法的签名,没有写实现,而其实可以给它写一个默认的实现
默认实现:
pub trait Summary {fn summarize(&self) -> String {String::from("(Read more...)")}
}
这里的默认实现就是返回一个字符串"(Read more…)"
由于这个方法在trait里面已经有一个默认实现了,所以在具体的类型上就可以直接采用这个默认实现,而不进行自己的实现。
以NewsArticle为例,原本它有自己的实现(或者叫做默认实现的重写的实现):
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{}, by {} ({})", self.headline, self.author, self.location)}
}
只要删掉这个具体实现就可以让NewsArticle用默认实现:
impl Summary for NewsArticle {}
还有一点需要知道,默认实现的方法可以调用trait中其它的方法,即使这些方法没有默认实现:
pub trait Summary {fn summerize_author(&self) -> Stringfn summarize(&self) -> String {String::from("(Read more from {}...)", self.summerize_author())}
}
在summarize的默认实现里调用了summerize_author,即使它只是一个签名,没有具体实现。但如果想要在类型上实现summerize的话就需要先写summerize_author的实现:
impl Summary for NewsArticle {fn summerize_author(&self) -> String {format!("@{}", self.author)}
}
PS:由于NewsArticle的summarize使用的是默认实现,所以就不需要在这里写summerize的默认实现了
这个写法有一点注意:无法从方法的重写实现里面调用默认的实现
相关文章:
【Rust自学】10.3. trait Pt.1:trait的定义、约束与实现
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 题外话:trait的概念非常非常非常重要!!!整个第10章全都是Rust的重难点!&#x…...
大数据高级ACP学习笔记(2)
钻取:变换维度的层次,改变粒度的大小 星型模型 雪花模型 MaxCompute DataHub...
K8s高可用集群之Kubernetes集群管理平台、命令补全工具、资源监控工具部署及常用命令
K8s高可用集群之Kubernetes管理平台、补全命令工具、资源监控工具部署及常用命令 1.Kuboard可视化管理平台2.kubectl命令tab补全工具3.MetricsServer资源监控工具4.Kubernetes常用命令 1.Kuboard可视化管理平台 可以选择安装k8s官网的管理平台;我这里是安装的其他开…...
【ArcGIS Pro二次开发实例教程】(2):BSM字段赋值
一、简介 一般的数据库要素或表格都有一个BSM字段,用来标识唯一值。 此工具要实现的功能是:按一定的规律(前缀中间的填充数字OBJECT码)来给BSM赋值。 主要技术要点包括: 1、ProWindow的创建,Label,Comb…...
OpenCV轮廓相关操作API (C++)
在OpenCV中,轮廓(contours)是图像处理中的一个重要概念,通常用于形状分析、物体检测等任务。OpenCV提供了多种与轮廓相关的API,可以在C中使用。 一.常用的与轮廓相关的操作及其对应的API函数 1.查找轮廓 findContou…...
[开源]自动化定位建图系统
系统状态机: 效果展示: 1、 机器人建图定位系统-基础重定位,定位功能演示 2、 机器人建图定位系统-增量地图构建,手动回环检测演示 3、敬请期待… 开源链接: 1、多传感器融合里程计 https://gitee.com/li-wenhao-lw…...
linux ansible部署
ansible部署完后,执行报错 # ansible one -i hosts -m ping dataos193 | FAILED! > {"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add …...
《Rust权威指南》学习笔记(二)
枚举enum 1.枚举的定义和使用如下图所示: 定义时还可以给枚举的成员指定数据类型,例如:enum IpAddr{V4(u8, u8, u8, u8),V6(String),}。枚举的变体都位于标识符的命名空间下,使用::进行分隔。 2.一个特殊的枚举Option࿰…...
Redis内存碎片
什么是内存碎片? 你可以将内存碎片简单地理解为那些不可用的空闲内存。 举个例子:操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数…...
Express 加 sqlite3 写一个简单博客
例图: 搭建 命令: 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…...
正则表达式进阶学习(一):环视、捕获分组与后向引用
一、环视(零宽断言) 理论部分 环视(零宽断言)是一种用于匹配位置而非字符的正则表达式技术。它的核心特点是:不消耗字符,只检查某个位置前后是否符合特定的条件。可以理解为,环视是在匹配前“…...
《Vue3 七》插槽 Slot
插槽可以让组件的使用者来决定组件中的某一块区域到底存放什么元素和内容。 使用插槽: 插槽的使用过程其实就是抽取共性、预留不同。将共同的元素、内容依然留在组件内进行封装;将不同的元素使用 slot 作为占位,让外部决定到底显示什么样的…...
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 一、线性表的基本概念 二、初始化线性表 三、销毁线性表 四、判定是否为空表 五、求线性表的长度 六、输出线性表 七、求线性表中某个数据元素值 八、按元素值查找 九、插入数据元素 十、删除数据元素 测试说明 通关代码 测…...
Linux C/C++编程-获得套接字地址、主机名称和主机信息
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com…...
USB kbtab linux 驱动代码
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/usb/input.h> #include <asm/unaligned.h> /* Pressure-threshold modules param code from */MODULE_AUTHOR(“xxx”); MODULE_DESCRIPTION(“…...
力扣 跳跃游戏
每次更新目标位置时,实际上是在做一个局部的最优选择,选择跳跃能够到达当前目标位置的最远位置。因为每次更新目标位置时,都是基于当前能跳跃到的最远位置,因此最终的结果是全局最优的。 题目 从前往后遍历,更新可以到…...
使用npm 插件[mmdc]将.mmd时序图转换为图片
使用npm 插件[mmdc]将.mmd时序图转换为图片 1. 安装 mmdc2. 转换为图片 可以使用 mmdc (Mermaid CLI)这个工具来将 .mmd 时序图(Mermaid语法描述的时序图)转换为图片,以下是使用步骤: 1. 安装 mmdc 确保…...
ffmpeg 常用命令
更详细请参考ffmpeg手册,下载ffmpegrelease版后在doc中就有,主页面。video filter 参考ffmpeg-filters.html -version -formats -demuxers -protocols -muxers -filters -devices —pix_fmts -codecs -sample_fmts -decoders -layouts -encoders -colors…...
从入门到实战:C 语言 strlen 函数通关指南
文章目录 一、strlen函数简介1. 函数构成2. 参数说明3. 使用示例 二、模拟实现strlen函数(从新手角度逐步升级改进)1. 基础版本(利用循环计数)2. 改进版本(利用指针相减)3. 递归版本(利用递归思…...
npm install --global windows-build-tools --save 失败
注意以下点 为啥下载windows-build-tools,是因为node-sass4.14.1 一直下载不成功,提示python2 没有安装,最终要安装这个,但是安装这个又失败,主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …...
告别原生JDBC的繁琐:用DBUtils的QueryRunner和BeanHandler重构你的Servlet登录逻辑
从JDBC泥潭到DBUtils优雅实践:Servlet登录逻辑的重构艺术 登录功能作为Web应用的基石,其代码质量直接影响系统的安全性和可维护性。传统ServletJDBC方案虽然直接,但存在大量重复代码和资源管理隐患。让我们看看如何用Apache Commons DBUtils这…...
别再当‘炼丹’黑盒侠了!用Grad-CAM给你的PyTorch/TensorFlow模型做个‘X光’检查
深度解密Grad-CAM:像外科手术般精准剖析CNN决策逻辑 当你的图像分类模型在测试集上表现优异,却在真实场景中频频出错时,作为开发者的你是否感到困惑?我们常常陷入一个怪圈:模型准确率很高,却不知道它究竟&q…...
Triton + RISC-V忱
. GIF文件结构 相比于 WAV 文件的简单粗暴,GIF 的结构要精密得多,因为它天生是为了网络传输而设计的(包含了压缩机制)。 当我们用二进制视角观察 GIF 时,它是由一个个 数据块(Block) 组成的&…...
html页面间调用
一、简单情况1、父页面通过iframe套子页面情况子页面通过window.parent调用父页面的函数2、多层嵌套window.top找到最顶层3、父界面通过open打开子界面子界面通过window.opener得到父界面二、复杂情况根据上述关系,进行各种组合,例如window.top.opener举…...
图像面积计算实战:四邻域标记与轮廓算法的对比与应用
1. 图像面积计算的基础概念 在图像处理领域,计算目标对象的面积是最基础也是最重要的任务之一。想象一下医生需要测量肿瘤的大小,或者质检员要计算产品缺陷的面积,这些都离不开准确的面积计算。我刚开始接触这个领域时,常常被各种…...
基于File-Based App开发MVP项目托
Issue 概述 先来看看提交这个 Issue 的作者是为什么想到这个点子的,以及他初步的核心设计概念。?? 本 PR 实现了 Apache Gravitino 与 SeaTunnel 的集成,将其作为非关系型连接器的外部元数据服务。通过 Gravitino 的 REST API 自动获取表结构和元数据&…...
从理论到实战:基于深度学习的模板匹配技术演进与核心实现
1. 模板匹配技术的演进之路 记得我第一次接触模板匹配是在2015年做工业质检项目时,当时用OpenCV的matchTemplate函数检测产品logo,遇到光照变化就频频误判。这种经历让我深刻体会到传统方法的局限性,也促使我深入研究深度学习的解决方案。 传…...
告别轮询!用wx.request的onChunkReceived在微信小程序里实现打字机效果的AI聊天
微信小程序流式交互实战:打造丝滑的AI打字机聊天效果 第一次在小程序里看到ChatGPT那种逐字输出的效果时,我盯着屏幕研究了半天——这流畅度简直像有人在远程打字。后来才发现,原来微信团队早在基础库2.10.0就埋下了onChunkReceived这个彩蛋。…...
为什么你的公平性测试总被算法团队驳回?——用因果公平性度量(CFM)替代传统统计公平性的工程实践(附FAIR-ML Pipeline v3.1源码)
第一章:大模型工程化中的模型公平性评估 2026奇点智能技术大会(https://ml-summit.org) 大模型在部署前必须通过系统化的公平性评估,否则可能在招聘筛选、信贷审批、司法辅助等高风险场景中放大社会偏见。公平性不是单一指标,而是涵盖群体公…...
Lattice Diamond IP核配置实战:从新建项目到生成BIT文件的完整流程
Lattice Diamond IP核配置实战:从新建项目到生成BIT文件的完整流程 在FPGA开发领域,Lattice Diamond以其轻量级和高效性赢得了不少开发者的青睐。不同于Xilinx和Altera(现Intel)的庞大工具链,Diamond提供了更简洁的工作…...
