学习Rust的第17天:Traits

news2025/1/17 23:02:47

Rust traits,包括自定义trait声明,trait边界,实现trait的返回类型,条件方法实现和blanket实现。Rust的多态性严重依赖于traits,这允许基于trait的分派和泛型编程。掌握traits使开发人员能够创建灵活的、可维护的代码,具有低运行时开销和可靠的编译时保证。

Introduction 介绍

Traits in Rust define a set of behaviors that types can implement, enabling polymorphism and code reusability, Yesterday we looked at the PartialOrd trait. Well we can create custom traits and implement them for structs… 

Rust 中的 taits 定义了一组类型可以实现的行为,从而实现多态性和代码可重用性。昨天我们研究了 PartialOrd 特征。 好吧,我们可以创建自定义特征并为结构实现它们......

We can use the trait keyword to define a trait

我们可以使用 Trait 关键字来定义特征

Let’s take a look at an example
我们来看一个例子

// Define a trait named 'Sound' with a method 'make_sound'.
trait Sound {
    fn make_sound(&self);
}

// Implement the 'Sound' trait for the type 'Dog'.
struct Dog;
impl Sound for Dog {
    fn make_sound(&self) {
        println!("Woof!");
    }
}

// Implement the 'Sound' trait for the type 'Cat'.
struct Cat;
impl Sound for Cat {
    fn make_sound(&self) {
        println!("Meow!");
    }
}

// A function that takes any type implementing the 'Sound' trait and makes it produce a sound.
fn animal_sound<T: Sound>(animal: T) {
    animal.make_sound();
}

fn main() {
    let dog = Dog;
    let cat = Cat;

    // Call the 'animal_sound' function with different types.
    animal_sound(dog);
    animal_sound(cat);
}
  • We define a trait named Sound with a method make_sound

我们使用 make_sound 方法定义一个名为 Sound 的特征。

  • We implement the Sound trait for the types Dog and Cat

我们为狗和猫类型实现了声音特征。

  • We define a function animal_sound that takes any type implementing the Sound trait and makes it produce a sound. 
    我们定义一个函数animal_sound,它接受任何实现声音特征的类型并使其产生声音。
  • In the main function, we create instances of Dog and Cat, and then we call animal_sound with both of these instances. 

在主函数中,我们创建 Dog 和 Cat 的实例,然后使用这两个实例调用animal_sound。

We had to declare how we wanted to use the sound function for each structure, but we can also specify default cases by doing something like this 
我们必须声明如何为每个结构使用声音函数,但我们也可以通过执行以下操作来指定默认情况

// Define a trait named 'Sound' with a method 'make_sound'.
trait Sound {
    //Default implementation
    fn make_sound(&self){
        println!("This is a default implementation");
    }
}

// Implement the 'Sound' trait for the type 'Dog'.
struct Dog;
impl Sound for Dog {
    //overridden
    fn make_sound(&self) {
        println!("Woof!");
    }
}

// Implement the 'Sound' trait for the type 'Cat'.
struct Cat;
impl Sound for Cat {
    //overridden
    fn make_sound(&self) {
        println!("Meow!");
    }
}

//uses the default implementation
struct Elephant;
impl Sound for Elephant{}

// A function that takes any type implementing the 'Sound' trait and makes it produce a sound.
fn animal_sound<T: Sound>(animal: T) {
    animal.make_sound();
}

fn main() {
    let dog = Dog;
    let cat = Cat;
    let elephant = Elephant;

    // Call the 'animal_sound' function with different types.
    animal_sound(dog);
    animal_sound(cat);
    animal_sound(elephant);
}

Output : 输出量:

Woof!
Meow!
This is a default implementation

Trait bounds 特质界限

In Rust, trait bounds are used to restrict generic types to types that implement certain traits. This ensures that the generic code can only be used with types that support the behavior defined by those traits. Traits can also be used directly as function arguments, allowing functions to accept any type that implements a particular trait.
在Rust中,trait bounds用于将泛型类型限制为实现某些trait的类型。这确保泛型代码只能与支持这些trait定义的行为的类型一起使用。trait也可以直接用作函数参数,允许函数接受实现特定trait的任何类型。

We saw this with yesterday’s find_max function
我们在昨天的 find_max 函数中看到了这一点

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

Here <T: PartialOrd> is the specified trait bound…
这里 <T: PartialOrd> 是指定的trait绑定.

Above, in the animal_sound function we have used a similar ideology fn animal_sound<T: Sound>(animal: T) in this line
在上面的 animal_sound 函数中,我们在这一行中使用了类似的思想 fn animal_sound<T: Sound>(animal: T)

fn animal_sound<T: Sound>(animal: T) {
    animal.make_sound();
}

This functon can also be declared as follows :
这个函数也可以声明如下:

fn animal_sound(animal: &impl Sound) {
    animal.make_sound();
}

Returning types that implement traits
返回实现trait的类型

We can do basically the same thing to return types through functions
我们基本上可以做同样的事情来通过函数返回类型

trait Sound {
    //Default implementation
    fn make_sound(&self){
        println!("This is a default implementation");
    }
}

// Implement the 'Sound' trait for the type 'Dog'.
struct Dog;
impl Sound for Dog {
    //overridden
    fn make_sound(&self) {
        println!("Woof!");
    }
}

// Implement the 'Sound' trait for the type 'Cat'.
struct Cat;
impl Sound for Cat {
    //overridden
    fn make_sound(&self) {
        println!("Meow!");
    }
}

fn return_animal(name: &str) -> Box<dyn Sound>{
  match name{
        "dog" => Box::new(Dog),
        "cat" => Box::new(Cat),
        _ => panic!("Unsupported animal type"),
    }
}

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>:

  • This function takes a string name and returns a boxed trait object implementing the Sound trait.
    这个函数接受一个字符串 name ,并返回一个实现 Sound trait的盒装trait对象。
  • It creates and returns a boxed instance of either Dog or Cat based on the value of name.
    它根据 name 的值创建并返回 Dog 或 Cat 的装箱实例。
  • The Box is used for dynamic memory allocation on the heap.
    Box 用于堆上的动态内存分配。
  • If we don’t use Box, we will get an error that looks like this :
    如果我们不使用 Box ,我们将得到一个错误,看起来像这样:
`match` arms have incompatible types
  • If the provided name doesn't match "dog" or "cat", it panics with an error message.
    如果提供的 name 与 "dog" 或 "cat" 不匹配,则会出现死机并显示错误消息。

fn return_cat() -> impl Sound :

  • This function returns any instance that implements the Sound trait, as of now we are returning a Cat type through this function.
    这个函数返回任何实现Sound trait的实例,到目前为止,我们通过这个函数返回 Cat 类型。

Output: 输出量:

Woof!
Meow!

Conditionally implementing methods
实现方法

If you take a look at yesterday’s article, We wrote this code:
如果你看看昨天的文章,我们写了这段代码:

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 f32
  println!("X: {}, Y: {}",point2.x(),point2.y);
}

Here we have two implementation blocks, One for a generic type which will return the X co-ordinate for every Point but the other implementation block only works for signed 32 bit integers. For us to get the y co-ordinate of a Point both the values of the struct will have to be a signed 32 bit integer
这里我们有两个实现块,一个用于泛型类型,它将返回每个Point的 X 坐标,但另一个实现块仅适用于有符号的32位整数。对于我们来说,要获得Point的 y 坐标,结构体的两个值都必须是有符号的32位整数

so here, I can get the x and y co-ordinate of point1 but only the x co-ordinate of point2 using methods
所以在这里,我可以得到 point1 的x和y坐标,但只能得到 point2 的x坐标,使用方法

Output: 输出量:

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

Blanket implementations 一揽子实施

Blanket implementations in Rust allow you to implement traits for all types that meet certain criteria, providing a default implementation for a trait across multiple types at once.
Rust中的Blanket实现允许您为满足某些条件的所有类型实现trait,同时为多个类型的trait提供默认实现。

use std::fmt::{Debug, Display};

// Define a generic function that displays the value.
fn display_value<T: Debug + Display>(value: T) {
    println!("Value: {}", value);
}

fn main() {
    let number = 42;
    let text = "Hello, Rust!";

    // Call the 'display_value' function with different types.
    display_value(number); // Output: Value: 42
    display_value(text);   // Output: Value: Hello, Rust!
}
  • We define a generic function display_value that takes any type T that implements both the Debug and Display traits.
    我们定义了一个泛型函数 display_value ,它接受任何实现 Debug 和 Display trait的类型 T 。
  • Rust’s standard library provides a blanket implementation of the Display trait for any type that implements Debug, allowing us to use display_value with types like i32 and &str directly.
    Rust的标准库为任何实现 Debug 的类型提供了 Display trait的全面实现,允许我们直接将 display_value 与 i32 和 &str 等类型一起使用。
  • When display_value is called with number (an i32) and text (a &str), it successfully displays their values using the Display implementation provided by the Debug trait.
    当使用 number (一个 i32 )和 text (一个 &str )调用 display_value 时,它会使用 Debug trait提供的 Display 实现成功显示它们的值。

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

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

相关文章

Unity射线实现碰撞检测(不需要rigbody组件)

使用physic.CapsulCast&#xff08;&#xff09;&#xff1b; 前面3个参数生成一个胶囊体&#xff0c; 向着发射方向&#xff0c;发射出一串的胶囊&#xff08;没有最大距离&#xff09; 有最大距离&#xff0c;可以节约性能开销。 physic.CapsulCast&#xff08;&#xff0…

BUUCTF---misc---[ACTF新生赛2020]outguess

1、下载附件&#xff0c;解压之后得到下面信息 2、查看图片属性&#xff0c;发现有个核心价值观编码&#xff1b;解码为abc 3、flag.txt提示 4、结合题目&#xff0c;这是一个outguess隐写 5、用kali先下载安装隐写库 6、使用命令-k(密钥)&#xff1b;-r(将图片里面的隐写信息…

数据结构练习-线性表定义与基本操作

----------------------------------------------------------------------------------------------------------------------------- 1. 线性表是( )。 A.一个有限序列&#xff0c;可以为空 B. 一个有限序列&#xff0c;不可以为空 C. 一个无限序列&#xff0c;可以为空…

(SH) HS-PEG-Cy5.5/CY7/CY5 巯基聚乙二醇Cy5.5/Cy7/Cy5

(SH) HS-PEG-Cy5.5/CY7/CY5 巯基聚乙二醇Cy5.5/Cy7/Cy5 【中文名称】花菁染料Cy5.5-聚乙二醇-巯醇 【英文名称】Cy5.5-PEG-SH 【结 构 】 【品 牌】碳水科技&#xff08;Tanshtech&#xff09; 【纯 度】95%以上 【保 存】-20℃ 【规 格】5mg&#xff0c;10m…

替换windows11 c:/windows/system32/下的dll

找到注册表中的这一项 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\icssvc\Settings 添加 WifiMaxPeers dword 值 32位 最大值是128 设置完成后重启icssvc服务 sc stop icssvc sc start icssvc 由于win11不小心装了preview版本&#xff0c;貌似这个8个最大的已经限定…

冯唐成事心法笔记 —— 知智慧

系列文章目录 冯唐成事心法笔记 —— 知己 冯唐成事心法笔记 —— 知人 冯唐成事心法笔记 —— 知世 冯唐成事心法笔记 —— 知智慧 文章目录 系列文章目录PART 4 知智慧 知可为&#xff0c;知不可为大势不可为怎么办为什么人是第一位的多谈问题&#xff0c;少谈道理用金字塔…

公园设施3D可视化:游园新体验,触手可及的未来

在数字化浪潮席卷全球的今天&#xff0c;我们的生活正在经历一场前所未有的变革。从智能家居到无人驾驶&#xff0c;从在线购物到虚拟现实&#xff0c;科技的力量正在不断刷新我们对世界的认知。而今&#xff0c;这一变革的触角已经延伸到了我们休闲娱乐的场所——公园。 想象一…

用6000万养废3个孩子,“精英教育”的遮羞布终于被掀开了

这几天刷到这样一条笔记。 主人公是一位60岁的香港驻上海的外资行高管&#xff0c;为了培养3个孩子&#xff0c;在他们身上花了6000万&#xff0c;但如今却没有一个孩子获得“成功”。 6000万的投入&#xff0c;换来3个孩子的一事无成&#xff0c;这样的教育算是失败吗&#x…

【Linux】信号的产生

目录 一. 信号的概念signal() 函数 二. 信号的产生1. 键盘发送2. 系统调用kill()raise()abort() 3. 软件条件alarm() 4. 硬件异常除零错误:野指针: 三. 核心转储 一. 信号的概念 信号是消息的载体, 标志着不同的行为; 是进程间发送异步信息的一种方式, 属于软中断. 信号随时都…

麒麟 Kylin V10 一键安装 Oracle 11GR2 单机 ASM(231017)

前言 Oracle 一键安装脚本&#xff0c;演示麒麟 Kylin V10 一键安装 Oracle 11GR2 单机 ASM&#xff08;231017&#xff09;过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&a…

mp4转mpg怎么转?3个好用软件推荐~

mpg文件格式&#xff0c;即MPEG&#xff08;Moving Picture Experts Group&#xff09;格式&#xff0c;起源于1993年&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;制定。当时视频传输的需求催生了这一高效的视频压缩标准&#xff0c;其设计目的在于在保持相对较好…

数据科学与大数据(学习记录)

这个专业或者方向&#xff0c;这个行业有一句话叫做工具决定下限&#xff0c;分析决定上限。通过数据解决问题的思路是最重要的&#xff0c;对于这类型人才.数据具有四大特性&#xff0c;一个是可以反复使用&#xff0c;一个是客观,量化,机器可处理.常见的分析流程&#xff0c;…

广州大学计算机网络实验报告五《网络程序设计》2023年

广州大学学生实验报告 开课学院及实验室&#xff1a; 学院 年级、专业、班 姓名 学号 实验课程名称 计算机网络实验 成绩 实验项目名称 网络程序设计 指导老师 &#xff08;1&#xff09;实验目的 通过程序模拟网桥的工作原理以及检验和的计算&am…

C++ 协程 学习笔记

协程的优势就是比线程切换的时间少很多&#xff0c;协程的切换时间是纳秒&#xff0c;而进行切换的时间是微秒 单线程用协程可以轻松的处理并发任务 co_yield和co_await可以将协程暂停下来 resume又把协程激活 如果c函数里有co_await、co_return、co_yield就会自动判定为协程…

可搜索加密:保护隐私的搜索技术

在信息化、数字化快速发展的今天&#xff0c;数据的安全性和隐私性已成为公众关注的焦点。随着云计算、大数据等技术的广泛应用&#xff0c;数据共享与协同工作日益普遍&#xff0c;但如何在确保数据安全性的前提下&#xff0c;实现数据的快速、高效检索&#xff0c;成为了一个…

一个Level 0富文本编辑器的进化历程

本文作者为 360 奇舞团前端开发工程师 一个Level 0富文本编辑器的进化历程 富文本编辑器是我们在生活中常用到的编辑工具&#xff0c;本文将为大家介绍富文本编辑器技术成长的历程&#xff0c;在最后会带大家利用document.execCommand实现一个简单的传统编辑器。 ps&#xff1a…

EasyCVR视频汇聚平台无法自动播放视频的原因排查与解决

国标GB28181协议EasyCVR安防视频监控平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流…

contenteditable可编辑功能,监听输入内容与回车操作

contenteditable 在div元素上添加contenteditable"true" 可以让div变成可编辑元素 <div class"word-block" contenteditable"true"></div>同时还支持回车换行 回车后就会生成一个div元素 添加 -webkit-user-modify: read-write-p…

spring DisposableBean作用,在spring Bean销毁时的钩子 以及@PreDestroy

DisposableBean 作用 在Spring框架中&#xff0c;DisposableBean是一个接口&#xff0c;它定义了一个单一的方法&#xff0c;用于在Spring容器关闭时或一个由Spring管理的Bean不再需要时执行特定的清理操作。当一个Bean实现了DisposableBean接口&#xff0c;Spring容器会在销毁…

VTC视频时序控制器原理以及Verilog实现

文章目录 一、前言二、视频时序控制原理三、Verilog实现3.1 代码3.2 仿真以及分析 一、前言 VTC&#xff08;Video Timing Controller&#xff09;是一种用于产生视频时序的控制器&#xff0c;在图像领域经常会输出各种分辨率和帧率的视频格式。因此为了方便&#xff0c;设置一…