学习 Rust 的第 17 天:如何使用traits定义抽象方法

大家好,

欢迎来到学习Rust的第17天,今天我们将研究Rust编程语言中的trait。

如果你还没有阅读昨天的文章,我建议你去读一下,因为我们今天学习的概念会建立在昨天学到的“通用类型”概念之上。

介绍

Rust中的trait定义了一组类型可以实现的行为,实现了多态性和代码可重用性。昨天我们看了PartialOrd trait。我们可以创建自定义trait,并为结构体实现它们…

我们可以使用trait关键字来定义一个trait。

让我们来看一个例子

// 定义一个名为'Sound'的trait,具有一个名为'make_sound'的方法。
trait Sound {fn make_sound(&self);
}// 为类型'Dog'实现'Sound' trait。
struct Dog;
impl Sound for Dog {fn make_sound(&self) {println!("汪汪!");}
}// 为类型'Cat'实现'Sound' trait。
struct Cat;
impl Sound for Cat {fn make_sound(&self) {println!("喵喵!");}
}// 一个接受任何实现了'Sound' trait的类型并让其发出声音的函数。
fn animal_sound<T: Sound>(animal: T) {animal.make_sound();
}fn main() {let dog = Dog;let cat = Cat;// 使用不同类型调用'animal_sound'函数。animal_sound(dog);animal_sound(cat);
}
  • 我们定义了一个名为Sound的trait,具有一个名为make_sound的方法。
  • 我们为DogCat类型实现了Sound trait。
  • 我们定义了一个animal_sound函数,该函数接受任何实现了Sound trait的类型,并使其发出声音。
  • main函数中,我们创建了DogCat的实例,然后调用了animal_sound来使用这两个实例。

我们必须声明我们想要如何为每个结构体使用声音函数,但我们也可以通过像这样做一些默认情况来指定默认情况

// 定义一个名为'Sound'的trait,具有一个名为'make_sound'的方法。
trait Sound {// 默认实现fn make_sound(&self) {println!("这是默认实现");}
}// 为类型'Dog'实现'Sound' trait。
struct Dog;
impl Sound for Dog {// 覆盖fn make_sound(&self) {println!("汪汪!");}
}// 为类型'Cat'实现'Sound' trait。
struct Cat;
impl Sound for Cat {// 覆盖fn make_sound(&self) {println!("喵喵!");}
}// 使用默认实现
struct Elephant;
impl Sound for Elephant {}// 一个接受任何实现了'Sound' trait的类型并让其发出声音的函数。
fn animal_sound<T: Sound>(animal: T) {animal.make_sound();
}fn main() {let dog = Dog;let cat = Cat;let elephant = Elephant;// 使用不同类型调用'animal_sound'函数。animal_sound(dog);animal_sound(cat);animal_sound(elephant);
}

输出:

汪汪!
喵喵!
这是默认实现

Trait 边界

在Rust中,trait边界用于将通用类型限制为实现了特定trait的类型。这确保了通用代码只能与支持这些trait定义的行为的类型一起使用。trait还可以直接用作函数参数,允许函数接受任何实现特定trait的类型。

我们在昨天的find_max函数中看到了这一点

fn find_max<T: PartialOrd>(x: T, y: T) -> T{if x > y {x}else{y}
}

这里的<T: PartialOrd>是指定的trait边界…

animal_sound函数中,我们使用了类似的理念fn animal_sound<T: Sound>(animal: T),在这一行中

fn animal_sound<T: Sound>(animal: T) {animal.make_sound();
}这个函数也可以这样声明:fn animal_sound(animal: &impl Sound) {animal.make_sound();
}

返回实现trait的类型

我们也可以通过函数返回类型来做基本相同的事情

trait Sound {// 默认实现fn make_sound(&self) {println!("这是默认实现");}
}// 为类型'Dog'实现'Sound' trait。
struct Dog;
impl Sound for Dog {// 覆盖fn make_sound(&self) {println!("汪汪!");}
}// 为类型'Cat'实现'Sound' trait。
struct Cat;
impl Sound for Cat {// 覆盖fn make_sound(&self) {println!("喵喵!");}
}fn return_animal(name: &str) -> Box<dyn Sound>{match name{"dog" => Box::new(Dog),"cat" => Box::new(Cat),_ => panic!("不支持的动物类型"),}
}fn return_cat() -> impl Sound{Cat
}fn main(){let dog = return_animal("dog");let cat = return_cat();dog.make_sound();cat.make_sound();
}

return_animal(name: &str) -> Box<dyn Sound>:

  • 这个函数接受一个字符串name,并返回一个实现了Sound trait的盒装trait对象。
  • 它根据name的值创建并返回DogCat的盒装实例。
  • Box用于在堆上进行动态内存分配。
  • 如果我们不使用Box,我们将得到一个错误,看起来像这样:

match arms have incompatible types

  • 如果提供的name不匹配"dog""cat",它会以错误消息抛出异常。

`fn return_cat() -> impl Sound

`:

  • 这个函数返回实现Sound trait的任何实例,现在我们通过这个函数返回一个Cat类型。

输出:

汪汪!
喵喵!

有条件地实现方法

如果你看看昨天的文章,我们写了这段代码:


struct Point<T>{x: T,y: T,
}impl<U> Point<U>{fn x(&self) -> &U {&self.x}
}impl Point<i32>{fn y(&self) -> i32{self.y}
}fn main(){let point1 = Point{x: 3, y: 10};let point2 = Point{x:3.4, y: 6.9};println!("X: {}, Y: {}",point1.x(),point1.y());//I cannot use the y() method for point2 as its data type is f32println!("X: {}, Y: {}",point2.x(),point2.y);
}

这里我们有两个实现块,一个是用于通用类型的,它将为每个Point返回X坐标,但另一个实现块仅对于32位有符号整数有效。要获取Point的y坐标,结构体的值必须都是32位有符号整数。

所以在这里,我可以获得point1的x和y坐标,但只能使用方法获取point2的x坐标

输出:

X: 3, Y: 10
X: 3.4, Y: 6.9

全局实现

Rust中的全局实现允许您为满足某些条件的所有类型实现trait,在多个类型上为trait提供默认实现。

use std::fmt::{Debug, Display};// 定义一个显示值的通用函数。
fn display_value<T: Debug + Display>(value: T) {println!("值: {}", value);
}fn main() {let number = 42;let text = "Hello, Rust!";// 使用不同类型调用'display_value'函数。display_value(number); // 输出: 值: 42display_value(text);   // 输出: 值: Hello, Rust!
}
  • 我们定义了一个通用函数display_value,它接受任何实现了DebugDisplay trait的类型T
  • Rust标准库为任何实现了Debug的类型提供了Display trait的全局实现,允许我们直接使用i32&str等类型调用display_value
  • 当使用number(一个i32)和text(一个&str)调用display_value时,它会成功地使用Debug trait提供的Display实现显示它们的值。

结论

最后,今天的文章简要介绍了Rust trait,包括自定义trait声明、trait边界、返回实现trait的类型、有条件的方法实现和全局实现。Rust的多态性在很大程度上依赖于trait,它允许基于trait的分发和泛型编程。掌握trait使开发人员能够创建灵活、易于维护的代码,具有低运行时开销和可靠的编译时保证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/7365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DS:链表的分类

欢迎来到Harper.Lee的学习世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu欢迎来后台找我哦&#xff01; 链表的结构⾮常多样&#xff0c;以下情况组合起来就有8种&#xff08;2 * 2 * 2&#xff09;链表结构。下面我们依次来认识它们吧&am…

大数据面试题(十):Hive的高频面试考点(二)

文章目录 Hive的高频面试考点 一、请说明Hive中 sort by ,order by ,cluster by ,distribute by各代表什么意思

Mysql 8.0 -- 最新版本安装(保姆级教程)

Mysql 8.0 -- 最新版本安装&#xff08;保姆级教程&#xff09; ​​ 一&#xff0c;下载Mysql数据库&#xff1a; 官网链接&#xff1a;https://www.mysql.com/downloads/ 二&#xff0c;安装Mysql: 三&#xff0c;找到Mysql安装目录&#xff1a; 找到mysql安装目录&#xf…

【信息系统项目管理师知识点速记】资源管理:获取资源

获取资源:项目成功的关键 在项目管理中,获取资源是确保项目成功的关键步骤之一。本文将探讨获取资源的过程,包括输入、工具与技术以及输出。 输入 1. 项目管理计划 资源管理计划: 提供了如何获取项目资源的指南。成本基准: 提供了项目活动的总体预算。采购管理计划: 包…

攻防世界-NewsCenter

题目信息 分析过程 题目打开是有个输入框可以用来输入搜索信息&#xff0c;初步判断是个sql注入的题目。接下来判断能否进行sql注入&#xff1a; 输入 hi&#xff0c;有搜索结果&#xff0c;如下图: 输入hi’,无结果&#xff0c;如下图&#xff1a; 初步判定是hi‘后面还有单引…

MongoDB聚合运算符:$toHashedIndexKey

MongoDB聚合运算符&#xff1a;$toHashedIndexKey 文章目录 MongoDB聚合运算符&#xff1a;$toHashedIndexKey语法举例角度的双曲正切 $toHashedIndexKey计算并返回输入表达式的哈希值&#xff0c;其使用的哈希函数与MongoDB创建哈希索引相同。哈希函数将键值或字符串映射到固定…

设计模式(2)创造型设计模式

创建型模式 创建型模式1.工厂模式1.1 抽象工厂模式&#xff08;Abstract factory&#xff09;1.2 工厂方法模式&#xff08;Factory Method&#xff09;1.3 简单工厂模式&#xff08;Simple Factory&#xff09; 2. 建造者模式&#xff08;Builder&#xff09;3. 原型模式&…

PHP介绍

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;PHP❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、PHP是什么&#xff1f; 二、 PHP 文件是什么&#xff1f; 三、PHP能做什么&#xff1f; 四、P…

[Android]四大组件简介

在 Android 开发中&#xff0c;“四大组件”&#xff08;Four Major Components&#xff09;是指构成 Android 应用程序的四种核心组件&#xff0c;它们通过各自的方式与系统交互&#xff0c;实现应用的多样功能。这些组件是&#xff1a;Activity、Service、Broadcast Receiver…

音响的无源辐射器

定义&#xff1a; 无源辐射器通常被用来调整低音&#xff0c;使得设计者能够调节音箱整体的音色。无源辐射器在音箱内主动单元对箱体内空气的带动下进行被动发声。 通常使用无源辐射器来代替倒相管都是用以调节较小箱体的音质和使其具有更好的低音表现。尤其是在一些情况下&a…

6个月小猫成长必备!福派斯无麸质幼猫粮评测

你知道吗&#xff1f;给小猫选择适合的猫粮是一件非常不容易但很重要的事情。那么&#xff0c;对于6个月大的小猫来说&#xff0c;什么样的猫粮是最适合它们的呢&#xff1f;&#x1f431; 我们首先要考虑的是猫粮的营养成分。6个月大的小猫正处于快速生长期&#xff0c;所以需…

远程连接是什么?

远程连接是指通过网络连接两个或多个设备&#xff0c;实现远程访问、控制或传输数据的技术。它在现代科技发展中起到了重要作用&#xff0c;使得我们可以随时随地与远程设备进行交互、管理和操作。 天联组网是一种高效的远程连接解决方案&#xff0c;它因为操作简单、跨平台应用…

07_Z Garbage Collector (ZGC)

Z垃圾收集器&#xff08;ZGC&#xff09;是一种可扩展的低延迟垃圾收集器。ZGC可以在不超过一毫秒的情况下并发执行所有昂贵的工作&#xff0c;而不会停止应用程序线程的执行。它适用于需要低延迟的应用程序。暂停时间与正在使用的堆大小无关。ZGC适用于从几百兆字节到16TB的堆…

git使用注意事项事项

以下操作均在gitee平台上实现 文章目录 1、本地仓库和远程仓库有冲突2、git提交自动忽略某些文件3、git无法push提交到远程仓库 1、本地仓库和远程仓库有冲突 在web端修改了文件内容或者删除了文件&#xff0c;本地仓库需要重新把远程仓库拉取到本地&#xff0c;或者强制提交到…

关于面试真题的压迫

1.请描述一下您在使用JavaScript进行DOM操作时&#xff0c;如何提高页面性能和用户体验&#xff1f; 使用事件委托&#xff1a;在父元素上监听事件&#xff0c;而不是为每个子元素都添加事件监听器。这样可以减少事件处理程序的数量&#xff0c;提高性能。 缓存DOM查询&#x…

Prometheus 2: 一个专门评估其他语言模型的开源语言模型(续集)

普罗米修斯的续集来了。 专有的语言模型如 GPT-4 经常被用来评估来自各种语言模型的回应品质。然而,透明度、可控制性和可负担性等考虑强烈促使开发专门用于评估的开源语言模型。另一方面,现有的开源评估语言模型表现出关键的缺点:1) 它们给出的分数与人类给出的分数存在显著差…

图像处理-图像平滑

图像平滑 前言一、概念介绍1.1 图像的平滑1.2 图像中噪声的分类1.3 MATLAB的添加噪音代码 二、空间域平滑滤波2.1 均值滤波2.2 原理计算 总结 前言 在图像的获取、传输和存储过程常常收到各种噪声的干扰和影响&#xff0c;使得图像的质量下降&#xff0c;为了获得高质量的数字…

读天才与算法:人脑与AI的数学思维笔记20_数学图灵测试

1. 数学图灵测试 1.1. 能不能将这种计算机证明语言翻译成易于与人交流的方式呢&#xff1f; 1.1.1. 剑桥大学的两位数学家蒂莫西高尔斯&#xff08;Timothy Gowers&#xff09;和莫汉加内萨林加姆&#xff08;Mohan Ganesalingam&#xff09;开展了此项研究 1.1.1.1. 他们决…

与Apolo共创生态: Apollo X企业自动驾驶解决方案的亮点

文章目录 前言技术革新的里程碑Apollo X企业自动驾驶解决方案的亮点Application X企业预制套件的多场景覆盖Studio X企业协同工具链的全周期支持第一阶段&#xff1a;上机系统构建第二阶段&#xff1a;POC搭建第三阶段&#xff1a;规模运营小结 共创生态&#xff0c;共享未来共…

catchtap 和 bindtap区别

做项目遇见的问题&#xff1a; 当你点击按钮触发事件后&#xff0c;当前用户和目标用户ID相同时&#xff0c;直接return&#xff0c;但是renturn时如何保证&#xff1a; 整个界面的触发函数是toDetailsTap&#xff0c;点我私聊按钮的触发函数是handleChat&#xff0c;如何保证…