尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【Rust自学】10.3. trait Pt.1:trait的定义、约束与实现
10.3 trait Pt.1trait的定义、约束与实现10.3.1. 什么是traittrait 的意思是特征、特质。trait 用来向 Rust 编译器描述某个类型具有哪些能力以及它可以与其他类型共享哪些行为。trait 以抽象方式定义共享行为。还有 trait bounds约束的概念它可以把泛型类型参数约束为实现了特定行为的类型。换句话说就是要求泛型类型参数实现某些 trait。Rust 中的 trait 与其他语言中的接口interface有些类似但仍有区别。10.3.2. 定义一个trait类型的行为由该类型本身可以调用的方法组成。有时不同类型具有相同的方法这时我们就说这些类型共享相同的行为。trait 提供了一种把方法组合在一起的方式从而定义实现某种目的所必需的行为。- 使用trait关键字定义 trait。trait 中的方法既可以只写方法签名以;结尾、没有方法体也可以提供默认实现后文会讲到- 一个 trait 可以有多个方法每个需要实现方提供的方法签名单独占一行并以;结尾- 对于没有默认实现的方法实现该 trait 的类型必须提供具体的方法体例如pub trait Summary { fn summarize(self) - String; }在trait前面加上pub表示它是公共的。这个 trait 名为Summary其中包含一个名为summarize的方法签名。除了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.rspub 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表示新闻文章。它有四个字段headline表示标题location表示地点author表示作者content表示内容结构体Tweet表示 X前身为 Twitter上的推文。它有四个字段username、content、reply和retweet这两个结构体类型当然不同它们的大多数字段也不同。但它们都可以有相同的行为——提供摘要Summary因此分别在这两个类型上实现了Summary。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()); }记住我们的代码写在lib.rs中在main.rs中使用之前需要先把它引入作用域。写法是use 你的package名::...::你需要的模块;你的 package 名就是Cargo.toml中的项目名把它复制过来即可。引入Summary是因为使用了Summarytrait 下的summarize方法引入Tweet是因为使用了Tweet结构体。看一下输出1 new tweet: horse_ebooks: of course, as you probably already know, people10.3.4. trait的约束想要为某个类型实现某个 trait前提条件是- 该类型本身例如Tweet或该 trait 本身例如让Vector实现本地的Summary必须在本地 crate 中定义- 不能为外部类型实现外部 trait。例如在本地 crate 中为标准库的Vector实现标准库的Displaytrait这个限制是语言一致性规则的一部分。更具体地说它是孤儿规则之所以这样命名是因为父类型并没有定义在当前 crate 中。这条规则确保其他人的代码不能随意破坏你的代码反之亦然。如果没有这条规则两个 crate 可以为同一个类型实现同一个 traitRust 就不知道该使用哪个实现。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 summarize_author(self) - String; fn summarize(self) - String { format!((Read more from {}...), self.summarize_author()) } }summarize的默认实现调用了summarize_author即使summarize_author只是一个签名、没有具体实现。但如果想为某个类型实现summarize就需要先实现summarize_authorimpl Summary for NewsArticle { fn summarize_author(self) - String { format!({}, self.author) } }PS由于NewsArticle使用了summarize的默认实现所以这里不需要再写summarize的实现。这种写法有一点需要注意无法从被覆盖的方法实现中调用默认实现。
RELATED

相关推荐

【Rust自学】10.4. trait Pt.2:trait作为参数和返回类型、trait bound

【Rust自学】10.4. trait Pt.2:trait作为参数和返回类型、trait bound

10.4 trait Pt.2:trait作为参数和返回类型、trait bound 10.4.1. 把trait作为参数 继续以 10.3 trait Pt.1:trait的定义、约束与实现 中的内容为例: pub trait Summary {fn summarize(&self) -> String; }pub struct NewsArticle {…

📅 2026/9/15 12:31:18
【Rust自学】10.5. 生命周期 Pt.1:生命周期的定义与意义、借用检查器与泛型生命周期

【Rust自学】10.5. 生命周期 Pt.1:生命周期的定义与意义、借用检查器与泛型生命周期

10.5 生命周期 Pt.1:生命周期的定义与意义、借用检查器与泛型生命周期 10.5.1. 什么是生命周期 Rust 中的每个引用都有自己的生命周期。生命周期的作用是让引用保持有效;换句话说,它就是引用保持有效的作用域。 在大多数情况下&#xff0c…

📅 2026/8/22 18:28:57
OpenClaw框架中的Self-Improving技能:AI Agent自主进化技术解析

OpenClaw框架中的Self-Improving技能:AI Agent自主进化技术解析

1. OpenClaw与Self-Improving技能概述OpenClaw作为新一代AI Agent开发框架,其核心价值在于提供了模块化的技能(Skill)体系。Self-Improving正是其中最引人注目的高级技能之一,它使AI Agent具备了持续进化的能力。不同于传统AI模型的静态表现,…

📅 2026/8/22 18:28:57
MORE NEWS

更多资讯

📰

C盘空间不足?PE环境无损分区调整扩容实操指南

C盘又飘红了?你大概率还没试过PE下的无损分区调整。Windows自带的磁盘管理像个半吊子,压缩卷只能从右往左腾出紧挨着C盘的空间,一旦你的D盘数据排布不凑巧,那个“扩展卷”按钮永远灰着。而PE环境下的无损分区调整,就是…

📰

Python requests库高级使用技巧与性能优化

1. 为什么我们需要关注requests调接口在Python生态中,requests库堪称HTTP客户端领域的"瑞士军刀"。作为一位常年与API打交道的开发者,我几乎每天都要用requests处理各种接口调用场景。但看似简单的requests.get()背后,却藏着许多新…

📰

Gitee凭据存储方案与Git安全认证实践

1. 为什么需要保存Git凭据?每次推送代码都要输入账号密码确实烦人。我在团队协作项目中深有体会——当你在终端和IDE之间频繁切换时,反复认证会打断工作流。Gitee作为国内主流代码托管平台,其实提供了多种凭据存储方案。凭据存储的本质是将认…

📰

Oracle到TDSQL迁移实战:金融级国产数据库落地指南

1. 项目概述:一次真实落地的国产数据库迁移实践我做过六次大型Oracle到国产分布式数据库的迁移,其中三次是金融核心系统,两次在政务云平台,最近一次就是这个从Oracle到腾讯TDSQL的升级项目。它不是PPT里的概念验证,而是…

📰

SpringBoot3多数据源方案实战与优化

1. 为什么我们需要SpringBoot3多数据源方案当业务发展到一定规模,单数据源架构往往会遇到性能瓶颈和业务隔离问题。我去年负责的一个电商后台系统就遇到了典型场景:订单库查询压力大影响促销活动,同时财务部门要求独立访问报表数据。这种场景…

📰

VS Code与Cursor中配置MATLAB调试环境的完整指南

如果你日常的工作流里同时有 Python 和 MATLAB,八成经历过这种撕裂感:写 Python 时用 VS Code,多光标、代码高亮、Git 集成、AI 补全样样顺手,切回 MATLAB 原生的那个复古编辑器,瞬间像回到了上个十年的开发环境。更别…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬