学习Rust的第17天:Traits

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 实现成功显示它们的值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springcloud Ribbion 实战

一、Ribbon单独使用&#xff0c;配置自动重试&#xff0c;实现负载均衡和高可用 1.spring-cloud-starter-netflix-ribbon 包引入 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</art…

20240425,模板

感觉比学C那会好了点&#xff0c;不怎么出现照着抄但是就是不能跑的情况&#xff0c;哭死&#xff0c;但是学的顺又不复习&#xff0c;第二天跟没学一样&#xff0c;笑死&#xff0c;要是能给我开个过目不忘的挂&#xff0c;爽的不要不要的 呵呵呵蠢女人&#xff0c;别忘了你C的…

服装厂生产ERP有哪些功能

在当今竞争激烈的服装行业中&#xff0c;企业如何在保证产品质量的同时提高生产效率和市场响应速度?答案在于智能化的生产管理。ERP(企业资源计划)系统作为现代企业管理的核心工具&#xff0c;对于服装厂而言&#xff0c;它的功能不仅需要全面&#xff0c;更要针对性强、操作简…

Python浅谈清朝秋海棠叶版图

1、清朝疆域概述&#xff1a; 清朝是我国最后一个封建王朝&#xff0c;其始于1616年建州女真部努尔哈赤建立后金&#xff0c;此后统一女真各部、东北地区。后又降服漠南蒙古&#xff0c;1644年入关打败农民起义军、灭南明&#xff0c;削三藩&#xff0c;复台湾。后又收外蒙&am…

展馆设计中必不可少的场景

1、一般场景展营造 一般场景是经过对实物进行概括、提炼&#xff0c;进行符号化、审美化的处理后引入展示现场&#xff0c;而并不是将与展品有关联的事物统统罗列其中。 2、复原场景营造 复原场景营造常用于博物馆、纪念馆陈列展示中。运用复原场景就是为了营造历史上曾存在的&…

java中2个List集合值和顺序完全一样,如果判断他们相等

和判断2个字符串是否相等一样&#xff0c;List可以通过equals来判断2个集合是否相等 示例代码如下&#xff1a; 1、相等的示例 2、顺序不一致 3、值不一致

简单使用优雅的程序计数器-StopWatch

一、引入hutool-core 5.8.18包 二、代码 public static void main(String[] args) throws InterruptedException {StopWatch stopWatch new StopWatch("测试StopWatch");stopWatch.start("任务1");// 任务1花费1000毫秒Thread.sleep(1000);stopWatch.st…

Python入门与进阶

基础语法语句 在线python代码运行网址 &#xff08;推荐使用python3网址&#xff09; 基础语法&输入输出 python等号赋值 赋值类型描述示例基本赋值使用等号&#xff08;&#xff09;进行赋值。x10同一个值给多个变量可以使用一个值来赋值给多个变量。xyz10多重赋值可以…

Bentley二次开发教程27-交互窗口-界面开发方法

界面设计概述 引言 在我们掌握了交互式工具的使用方法后&#xff0c;在使用过程中会发现&#xff1a;虽然工具中拥有多种交互的手段&#xff0c;但仅凭工具中鼠标&#xff0c;特殊按键与信息提示等交互方法&#xff0c;没有办法同时对多个信息进行展示&#xff0c;也不够直观…

Redis底层数据结构之IntSet

目录 一、概述二、IntSet结构三、自动升级 redis底层数据结构已完结&#x1f44f;&#x1f44f;&#x1f44f;&#xff1a; ☑️redis底层数据结构之SDS☑️redis底层数据结构之ziplist☑️redis底层数据结构之quicklist☑️redis底层数据结构之Dict☑️redis底层数据结构之Int…

java开发之路——用户管理中心_简单初始化

用户管理中心_简单初始化 (一) 初始化项目1. 使用 Ant Design Pro(现成的管理系统) 进行前端初始化2. 后端初始化三种初始化java项目 (二) 遇到的问题【问题1】Ant design pro页面打不开&#xff0c;一直在budiling控制台出现错误error-./src/components/index.ts【问题2】初始…

ROS python实现乌龟跟随

产生两只乌龟&#xff0c;中间的乌龟(A) 和 左下乌龟(B), B 会自动运行至A的位置&#xff0c;并且键盘控制时&#xff0c;只是控制 A 的运动&#xff0c;但是 B 可以跟随 A 运行 乌龟跟随实现的核心&#xff0c;是乌龟A和B都要发布相对世界坐标系的坐标信息&#xff0c;然后&am…

按钮获取验证码倒计时60秒

把倒计时存在缓存里刷新页面依旧是接着倒计时 <el-buttonsize"large"class"btnStyle":class"btnStyleClass":style"buttonStyle":disabled"countdownActive"click"handleClick">{{ buttonText }}</el-b…

算法-KMP算法

时间复杂度&#xff1a; public int strStr(String haystack, String needle) {int[] next new int[needle.length()];//next数组的生成next[0] 0;int prefixLen 0;//共同前后缀长度int i 1, j 1;//i,j复用while (i < needle.length()) {if (needle.charAt(prefixLen)…

Shader实战(3):贴图像素化风格实现

话不多说&#xff0c;将以下shader赋给材质贴上贴图即可。 Shader "HQY/Shader2" //自己改名 {Properties{_Diffuse ("Diffuse", Color) (1,1,1,1)_MainTex ("MainTex", 2D) "white" {}_Specular("Specular", Color) (…

AI伙伴是什么

AI伙伴&#xff0c;或称为人工智能伙伴&#xff0c;是指能够执行特定任务、协助人类活动&#xff0c;甚至进行社交互动的智能系统。 编辑搜图 请点击输入图片描述&#xff08;最多18字&#xff09; AI伙伴通常是通过集成了先进的技术如语音识别、语义理解和图像识别等来实现与…

ubuntu扩展根目录磁盘空间

ubuntu扩展根目录磁盘空间 扩展虚拟机磁盘空间 查看现有磁盘状态 查询现有分区状态&#xff0c;/dev/sda是我们要扩展的磁盘 fdisk -l 开始进行磁盘空间的扩容 parted /dev/sda#扩展3号分区的空间 resizepart 3刷新分区空间 resize2fs /dev/sda3查询扩展结果&#xff0c;…

Golang GMP解读

概念梳理 1. 1 线程 通常语义中的线程&#xff0c;指的是内核级线程&#xff0c;核心点如下&#xff1a; 是操作系统最小调度单元&#xff1b;创建、销毁、调度交由内核完成&#xff0c;cpu 需完成用户态与内核态间的切换&#xff1b;可充分利用多核&#xff0c;实现并行. …

HTTP 网络协议请求的消息结构,具体详解(2024-04-25)

一、简介 HTTP 是基于客户端/服务端&#xff08;C/S&#xff09;的架构模型&#xff0c;通过一个可靠的链接来交换信息&#xff0c;是一个无状态的请求/响应协议。 HTTP 消息是客户端和服务器之间通信的基础&#xff0c;它们由一系列的文本行组成&#xff0c;遵循特定的格式和…

热门项目!知识付费小程序源码系统 带完整的安装代码包以及安装部署教程

近年来&#xff0c;随着在线教育、知识分享等领域的蓬勃发展&#xff0c;知识付费市场逐渐壮大。越来越多的用户愿意为高质量的知识内容付费&#xff0c;而企业和个人也看到了知识付费的巨大商机。然而&#xff0c;对于许多没有技术背景的用户来说&#xff0c;搭建一个稳定、易…