Rust特征

一、Rust特征是什么、怎么用

1、Rust特征是什么

我认为Rust特征和Java中的接口类似,但是扩展了语义

特征定义了一组可以被共享的行为,只要实现了特征,你就能使用这组行为

2、Rust特征怎么使用

(1)特征定义

pub trait Summary {//Summary 是特征名称fn summarize(&self) -> String;//和接口类似,不需要具体实现方法体
}

带有默认实现的特征定义

pub trait Summary {fn summarize(&self) -> String {String::from("(Read more...)")}
}

这样使得实现了该特征的类型,自动具备了默认的特征行为,当然也可以覆盖重写优先调用覆盖重写的特征行为

(2)为类型实现特征

pub trait Summary {fn summarize(&self) -> String;
}
pub struct Post {//类型可以不仅仅是结构体,是 类型 就可以定义特征pub title: String, // 标题pub author: String, // 作者pub content: String, // 内容
}impl Summary for Post {fn summarize(&self) -> String {format!("文章{}, 作者是{}", self.title, self.author)}
}pub struct Weibo {pub username: String,pub content: String
}impl Summary for Weibo {//为Weibo 实现特征Summary,则Weibo具有Summary的特征和对应特征的行为fn summarize(&self) -> String {format!("{}发表了微博{}", self.username, self.content)}
}
fn main() {let post = Post{title: "Rust语言简介".to_string(),author: "Sunface".to_string(), content: "Rust棒极了!".to_string()};let weibo = Weibo{username: "sunface".to_string(),content: "好像微博没Tweet好用".to_string()};println!("{}",post.summarize());println!("{}",weibo.summarize());
}

为类型实现特征之后,我们来调用对应特征的行为来看看

文章Rust语言简介, 作者是Sunface
sunface发表了微博好像微博没Tweet好用

这样我们就完成了特征的基本定义和使用

(3)使用特征作为函数参数

这时候感觉特征有点多态的味道了,但不是Java继承的那种多态,像是Golang的那种组合多态。

可以使用任何实现了 Summary 特征的类型作为该函数的参数

pub trait Summary {fn summarize(&self) -> String;
}
pub struct Post {pub title: String, // 标题pub author: String, // 作者pub content: String, // 内容
}impl Summary for Post {fn summarize(&self) -> String {format!("文章{}, 作者是{}", self.title, self.author)}
}pub struct Weibo {pub username: String,pub content: String
}impl Summary for Weibo {fn summarize(&self) -> String {format!("{}发表了微博{}", self.username, self.content)}
}
fn main() {let post = Post{title: "Rust语言简介".to_string(),author: "Sunface".to_string(), content: "Rust棒极了!".to_string()};notify(&post);
}pub fn notify(item: &impl Summary) {println!("Breaking news! {}", item.summarize());
}

如果我们用特征作为返回值会怎么样呢,后面我们在讨论这件事情

(4)特征约束

其实impl Summary就是特质约束的一种语法糖写法,约束了你传递的参数需要实现Summary特征。
当然还可以是别的写法,形如 T: Summary 被称为特征约束,例如:

pub fn notify<T: Summary>(item: &T) {println!("Breaking news! {}", item.summarize());
}

如果涉及多个约束条件,那么我们可以这么写

pub fn notify(item: &(impl Summary + Display)) {}//Summary和Display两个约束
pub fn notify<T: Summary + Display>(item: &T) {}
fn some_function<T, U>(t: &T, u: &U) -> i32where T: Display + Clone,U: Clone + Debug
{}

前面的写法意义上是一样的,只是语法不同。

(5)使用特征约束有条件地实现方法或特征

特征约束,可以让我们在指定类型 + 指定特征的条件下去实现方法,例如:

use std::fmt::Display;struct Pair<T> {x: T,y: T,
}impl<T> Pair<T> {fn new(x: T, y: T) -> Self {Self {x,y,}}
}impl<T: Display + PartialOrd> Pair<T> {fn cmp_display(&self) {if self.x >= self.y {println!("The largest member is x = {}", self.x);} else {println!("The largest member is y = {}", self.y);}}
}

上面代码的意思是

cmp_display 方法,并不是所有的 Pair 结构体对象都可以拥有,只有 T 同时实现了 Display +
PartialOrd 的 Pair 才可以拥有此方法

(5)派生特征(引入特征)

形如 #[derive(Debug)] ,这种是一种特征派生语法,被 derive 标记的对象会自动实现对应的默认特征代码继承相应的功能

// 为Centimeters引入结构体比较的特征,使得Centimeters可以进行比较
#[derive(PartialEq, PartialOrd)]
struct Centimeters(f64);// 为Inches引入结构体打印的特征
#[derive(Debug)]
struct Inches(i32);impl Inches {fn to_centimeters(&self) -> Centimeters {let &Inches(inches) = self;Centimeters(inches as f64 * 2.54)}
}// 引入结构体打印、结构体比较的特征功能#[derive(Debug,PartialEq,PartialOrd)]
struct Seconds(i32);fn main() {let _one_second = Seconds(1);println!("One second looks like: {:?}", _one_second);let _this_is_true = (_one_second == _one_second);let _this_is_false = (_one_second > _one_second);let foot = Inches(12);println!("One foot equals {:?}", foot);let meter = Centimeters(100.0);let cmp =if foot.to_centimeters() < meter {"smaller"} else {"bigger"};println!("One foot is {} than one meter.", cmp);
}

(6)使用特征作为返回参数?

前面我们提到了特征可以参数函数参数进行传递,实现了类似Golang组合继承的效果,如果我们采用特征作为返回参数可以吗?
来看一段代码

pub trait Summary {fn summarize(&self) -> String;
}
pub struct Post {pub title: String, // 标题pub author: String, // 作者pub content: String, // 内容
}impl Summary for Post {fn summarize(&self) -> String {format!("文章{}, 作者是{}", self.title, self.author)}
}pub struct Weibo {pub username: String,pub content: String
}impl Summary for Weibo {fn summarize(&self) -> String {format!("{}发表了微博{}", self.username, self.content)}
}
fn returns_summarizable(switch: bool) -> impl Summary {if switch {Post {title: String::from("Penguins win the Stanley Cup Championship!",),author: String::from("Iceburgh"),content: String::from("The Pittsburgh Penguins once again are the best \hockey team in the NHL.",),}} else {Weibo {username: String::from("horse_ebooks"),content: String::from("of course, as you probably already know, people",),}}
}
fn main() {_a =returns_summarizable(true);
}

上面代码中,Weibo和Post都已经实现了Summary特征,运行一下

`if` and `else` have incompatible types
expected struct `Post`, found struct `Weibo`

报错提示我们 if 和 else 返回了不同的类型。只有相同类型,才可以使用imply trait的方式。如果想要实现返回 “实现相同特征”的 “不同的类型”,需要使用特征对象,下一篇我们再讲特征对象

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

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

相关文章

白话机器学习1:分类问题中的评价指标

机器学习中的评价指标非常多&#xff0c;它们用来衡量模型的性能和预测能力。不同类型的机器学习任务可能需要不同的评价指标。以下是一些常见的评价指标&#xff0c;按照不同类型的机器学习任务分类&#xff1a; 对于分类问题&#xff1a; 准确率&#xff08;Accuracy&#…

[NeurIPS-23] GOHA: Generalizable One-shot 3D Neural Head Avatar

[pdf | proj | code] 本文提出一种基于单图的可驱动虚拟人像重建框架。基于3DMM给粗重建、驱动结果&#xff0c;基于神经辐射场给细粒度平滑结果。 方法 给定源图片I_s和目标图片I_t&#xff0c;希望生成图片I_o具有源图片ID和目标图片表情位姿。本文提出三个分支&#xff1a;…

WPF —— MVVM command如何传递参数

点击按钮把窗体关闭 把页面的控件传递到自定义指令的函数中 FindAncestor 找到该组件的祖先元素 AncestorType{x:Type Window} 祖先元素类型为window CommandParameter 自定义指令传递参数 自定义指令 public class MyCommand : ICommand {public event Ev…

pytorch中创建maskrcnn模型

0.模型输入/输出参数参见 链接: pytorch的mask-rcnn的模型参数解释 核心代码 GeneralizedRCNN(这里以mask-rcnn来解释说明) # 通过输入图像获取fpn特征图,注意这里的backbone不是直接的resnet,而是fpn化后的 features self.backbone(images.tensors) # 由于是mask-rcnn,故而…

SpringCloud系列(10)--Eureka集群原理及搭建

前言&#xff1a;当注册中心只有一个&#xff0c;而且当这个注册中心宕机了&#xff0c;就会导致整个服务环境不可用&#xff0c;所以我们需要搭建Eureka注册中心集群来实现负载均衡故障容错 Eureka架构原理图 1、Eureka集群原理 2、创建Eureka Server端服务注册中心模块 (1)在…

R语言使用sjPlot包优雅绘制回归模型的交互效应图

交互作用效应(p for Interaction)在SCI文章中可以算是一个必杀技&#xff0c;几乎在高分的SCI中必出现&#xff0c;因为把人群分为亚组后再进行统计可以增强文章结果的可靠性&#xff0c;进行可视化后可以清晰的表明变量之间的关系。不仅如此&#xff0c;交互作用还可以使用来进…

Dockerfile实战(SSH、Systemctl、Nginx、Tomcat)

目录 一、构建SSH镜像 1.1 dockerfile文件内容 1.2 生成镜像 1.3 启动容器并修改root密码 二、构建Systemctl镜像 2.1 编辑dockerfile文件 ​编辑2.2 生成镜像 2.3 启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;然后进行初始化 2.4 进入容器验证 三、…

妙手解迭:React Store数据迭代难题

在 React 中&#xff0c;当 store 中的数据无法迭代时,可以尝试以下几种方案: 检查数据结构 首先,请检查 store 中的数据结构是否符合预期。如果数据结构是一个普通对象而不是数组或者其他可迭代对象,那么无法直接使用 for...of 或 for...in 等方式进行迭代。 使用 Object.k…

安卓Clean Architecture:实现模块化与可测试性的软件设计方法

摘要 在不断变化的移动开发领域中&#xff0c;构建一个既灵活又可维护的应用至关重要。安卓Clean Architecture提供了一种强有力的设计方法论来实现这一目标。本文将概述Clean Architecture的核心概念、分层架构以及其优缺点&#xff0c;并通过代码示例展示如何在Android项目中…

照片误删怎么办?华为手机删除的照片如何恢复?

我们在使用华为手机时&#xff0c;可能会因为各种原因不小心删除一些照片。如果这些照片对我们来说很重要&#xff0c;那么恢复它们是非常必要且急迫的。那么华为手机删除的照片如何恢复呢&#xff1f;本文将为您介绍3种恢复华为手机中误删照片的方法。 如何恢复华为手机中被删…

gin学习1-7

package mainimport ("github.com/gin-gonic/gin""net/http" )// 响应json还有其他响应差不多可以去学 func _string(c *gin.Context) {c.String(http.StatusOK, "lalal") } func _json(c *gin.Context) {//json响应结构体type UsetInfo struct …

Codeforces Round 941 (Div. 2)(A-D)

A. Card Exchange&#xff08;思维 Problem - A - Codeforces 题目大意&#xff1a; 给定n张牌&#xff0c;每次选k张相同的牌&#xff0c;把他们变成k-1张任意的牌&#xff0c;求最后手中最少能有几张牌。 思路&#xff1a; 直接判断这n张牌当中有没有k张一样的牌&#xff0c…

【java9】java9新特性之接口的私有方法

在Java 9中&#xff0c;接口可以包含私有方法&#xff08;包括静态私有方法和实例私有方法&#xff09;。这允许接口的设计者创建一些辅助方法&#xff0c;这些方法只能被接口中的其他方法所使用&#xff0c;而不能被实现该接口的类直接访问。 Java7 Java7及之前 &#xff0c…

软件项目管理的主要内容是什么?

目录 一、项目需求分析 二、项目计划制定 三、资源分配与调度 四、进度监控与控制 五、质量管理与保障 六、风险管理与应对 七、沟通协调与团队管理 八、项目收尾与总结 九、其他 一、项目需求分析 项目需求分析是软件项目管理的起始点&#xff0c;它涉及与客户的深入沟…

从Grafana支持的认证方式分析比较IAM产品现状与未来展望

调研报告 标题&#xff1a;从Grafana支持的认证方式分析比较IAM产品现状与未来展望 概述 本报告首先概述了评价IAM&#xff08;Identity and Access Management&#xff09;产品的主要因素&#xff0c;并基于Grafana支持的认证方式&#xff0c;引出对IAM产品的深入探讨。通过…

求解素数-埃氏筛选

什么是素数了?就是除了0和1之外,一个数只能由1和它本身相乘得来,这就是素数 第一种暴力求解: package com.fan.suanfati;import java.util.Scanner;public class SuShu {public static void main(String[] args) {System.out.println("请输入数字,以便求出该数字内的素数…

golang调用钉钉发送群机器人消息

golang调用钉钉发送群机器人消息 因为当时用的wire依赖注入&#xff0c;所以需要用多个钉钉机器人的时候&#xff0c;就把每个client实例加入到了map里 package dingtype Client interface {// SendMessage 发送钉钉SendMessage(s string, at ...string) error }type ClientO…

ubuntu22.04 修改内核源码教程

1. 确认当前内核版本 uname -a 2. 去ubuntu官网下载对应版本内核源码 6.5.0-28.29 : linux package : Ubuntu (launchpad.net) 3. 准备编译环境 sudo apt-get install libncurses5-dev libssl-dev build-essential openssl flex bison libelf-dev tar -xzvf linux_6.5.…

Spring Boot整合Redisson的两种方式

项目场景 Spring Boot整合Redisson的两种方式&#xff0c;方式一直接使用yml配置&#xff0c;方式二创建RedissonConfig配置类。 前言 redisson和redis区别&#xff1a; Redis是一个开源的内存数据库&#xff0c;支持多种数据类型&#xff0c;如字符串、哈希、列表、集合和有序…

Android常用的延迟执行任务及轮询定时任务的几种方式

Android常用的延迟执行任务及轮询定时任务的几种方式 Executor 的 execute() 方法:向线程池中提交任务(异步执行)代码示例Timer 的 schedule() 方法:安排执行任务、延时执行任务、轮询定时任务代码示例ScheduledExecutorService:提供了一系列方法用于安排任务的延迟执行、周…