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) -> i32
    where 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.mfbz.cn/a/581623.html

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

相关文章

redis ZRANGE 使用最详细文档

环境&#xff1a; redis_version:7.2.2 本文参考 redis 官方文档1 语法 ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]参数含义key是有序集合的键名start stop在不同语境下&#xff0c;可用值不一样BYSCORE | BYLEX按照分数查询 | 相…

【汇编】#6 80x86指令系统其二(串处理与控制转移与子函数)

文章目录 一、串处理指令1. 与 REP 协作的 MOVS / STOS / LODS的指令1.1 重复前缀指令REP1.2 字符串传送指令&#xff08;Move String Instruction&#xff09;1.2 存串指令&#xff08;Store String Instruction&#xff09;1.3 取字符串指令&#xff08;Load String Instruct…

[华为OD]给定一个 N*M 矩阵,请先找出 M 个该矩阵中每列元素的最大值 100

题目&#xff1a; 给定一个 N*M 矩阵&#xff0c;请先找出 M 个该矩阵中每列元素的最大值&#xff0c;然后输出这 M 个值中的 最小值 补充说明&#xff1a; N 和 M 的取值范围均为&#xff1a;[0, 100] 示例 1 输入&#xff1a; [[1,2],[3,4]] 输出&#xff1a; 3 说…

【UE5】数字人基础

这里主要记录一下自己在实现数字人得过程中涉及导XSens惯性动捕&#xff0c;视频动捕&#xff0c;LiveLinkFace表捕&#xff0c;GRoom物理头发等。 一、导入骨骼网格体 骨骼网格体即模型要在模型雕刻阶段就要雕刻好表捕所需的表情体(blendshape)&#xff0c;后面表捕的效果直…

机器学习:基于Sklearn框架,使用逻辑回归对由心脏病引发的死亡进行预测分析

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

数据分析-----方法论

什么是数据分析方法 数据分析方法&#xff1a;将零散的想法和经验整理成有条理的、系统的思路&#xff0c;从而快速地解决问题。 案例&#xff1a; 用户活跃度下降 想法&#xff1a; APP出现问题&#xff1f;去年也下降了吗&#xff1f;是所有的人群都在下降吗&#xff1f…

vscode中新建vue项目

vscode中新建vue项目 进入项目文件夹&#xff0c;打开终端 输入命令vue create 项目名 如vue create test 选择y 选择vue3 进入项目&#xff0c;运行vue项目 输入命令cd test和npm run serve

Spark RDD

Spark RDD操作 Spark执行流程 在上一讲中&#xff0c;我们知道了什么是Spark&#xff0c;什么是RDD、Spark的核心构成组件&#xff0c;以及Spark案例程序。在这一讲中&#xff0c;我们将继续需要Spark作业的执行过程&#xff0c;以及编程模型RDD的各种花式操作&#xff0c;首…

蓝桥杯ctf2024 部分wp

数据分析 1. packet 密码破解 1. cc 逆向分析 1. 欢乐时光 XXTEA #include<stdio.h> #include<stdint.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2)(y>>3^z<<4))^((sum^y)(key[(p&3)^e]^z))) void btea(unsigned int* v…

【Python 对接QQ的接口】简单用接口查询【等级/昵称/头像/Q龄/当天在线时长/下一个等级升级需多少天】

文章日期&#xff1a;2024.04.28 使用工具&#xff1a;Python 类型&#xff1a;QQ接口 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&#xff09;&…

纯血鸿蒙APP实战开发——监听HiLog日志实现测试用例验证

介绍 日常中在进行测试用例验证时&#xff0c;会出现部分场景无法通过判断UI的变化来确认用例是否正常运行&#xff0c;我们可以通过监听日志的方式来巧妙的实现这种场景。本示例通过监听hilog日志的回调&#xff0c;判断指定日志是否打印&#xff0c;来确定测试用例的执行结果…

Linux 第十三章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

IDEA主题美化【保姆级】

前言 一款好的 IDEA 主题虽然不能提高我们的开发效率&#xff0c;但一个舒适简单的主题可以使开发人员更舒适的开发&#xff0c;时常换一换主题可以带来不一样的体验&#xff0c;程序员的快乐就这么简单。话不多说&#xff0c;先上我自己认为好看的主题设置。 最终效果图: 原…

7.Prism框架之对话框服务

文章目录 一. 目标二. 技能介绍① 什么是Dialog?② Prism中Dialog的实现方式③ Dialog使用案例一 (修改器)④ Dialog使用案例2(异常显示窗口) 一. 目标 1. 什么是Dialog?2. 传统的Dialog如何实现?3. Prism中Dialog实现方式4. 使用Dialog实现一个异常信息弹出框 二. 技能介…

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

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

百度竞价开户详解:步骤、优势与注意事项

随着互联网的普及&#xff0c;网络营销已成为企业不可或缺的一部分。其中&#xff0c;百度竞价作为一种高效的网络推广方式&#xff0c;受到了越来越多企业的青睐。本文将详细介绍百度竞价开户的流程、优势以及注意事项&#xff0c;帮助企业更好地利用这一工具提升品牌知名度和…

ubuntu安装Anaconda安装及conda使用

一. 安装anaconda3详细教程 1、下载镜像 清华大学开源软件镜像站下载地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 下拉到最低端选择Linux&#xff0c;选择最新版&#xff08;32/64位&#xff09;下载。这里我下载的是版本Anaconda3-4.3.30-Linux…

Spire.PDF for .NET【文档操作】演示:创建 PDF/A 并插入图像的超链接

PDF/A 广泛用于 PDF 格式的长期归档。通过使用Spire.PDF&#xff0c;您可以直接创建PDF/A文件。本文主要介绍如何建立PDF/A文件&#xff1b;它还将演示如何在 C# 中添加图像和插入图像的超链接。 确保Spire.PDF for .NET&#xff08;版本 2.9.43 或更高版本&#xff09;已正确…

TikTok引流中海外云手机的实用功能分享

在当下&#xff0c;TikTok已成为全球范围内最受欢迎的社交媒体平台之一&#xff0c;拥有着庞大的用户群体和潜在的商业机会。为了在TikTok上实现更好的引流效果&#xff0c;利用海外云手机成为了一个明智的选择。接下来&#xff0c;我们将深入探讨海外云手机的功能以及它如何助…

神经网络的反向传播

梯度下降算法 &#x1f525;我们来看一下神经网络中的梯度下降算法&#x1f525; 梯度下降法是一种优化算法&#xff0c;用于寻找目标函数的最小值。梯度是一个向量&#xff0c;表示某一函数在该点处的方向导数沿着该方向取得最大值&#xff0c;即函数在该点处变化最快的方向…
最新文章