当前位置: 首页 > news >正文

【Rust练习】18.特征 Trait

练习题来自:https://practice-zh.course.rs/generics-traits/traits.html

1


// 完成两个 `impl` 语句块
// 不要修改 `main` 中的代码
trait Hello {fn say_hi(&self) -> String {String::from("hi")}fn say_something(&self) -> String;
}struct Student {}
impl Hello for Student {
}
struct Teacher {}
impl Hello for Teacher {
}fn main() {let s = Student {};assert_eq!(s.say_hi(), "hi");assert_eq!(s.say_something(), "I'm a good student");let t = Teacher {};assert_eq!(t.say_hi(), "Hi, I'm your new teacher");assert_eq!(t.say_something(), "I'm not a bad teacher");println!("Success!")
}

特征类似于 C++ 中的纯虚类(因为特征本身无法实例化)。Rust 将“继承”改为了“实现了某个特征”,让面向对象的这套体系更灵活了。但是我个人觉得这套体系有点过于复杂了,似乎是在掩盖本身的设计缺陷。

这里将对应的方法实现即可。

struct Student {}
impl Hello for Student {fn say_something(&self) -> String{String::from("I'm a good student")}
}
struct Teacher {}
impl Hello for Teacher {fn say_hi(&self) -> String {String::from("Hi, I'm your new teacher")}fn say_something(&self) -> String{String::from("I'm not a bad teacher")}
}

2


// `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)}
}// 添加一些属性让代码工作
// 不要修改其它代码!
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);
}

Centimeters需要实现Debug PartialEq PartialOrd特征,答案都写在上面了,当然你要是非得自己实现一下那我也没意见。

// 添加一些属性让代码工作
// 不要修改其它代码!
#[derive(Debug)]
#[derive(PartialEq, PartialOrd)]
struct Seconds(i32);

从 C++ 的角度看这几个问题,Debug是老大难问题了,基本只能靠类自己去实现打印函数,当然我也觉得这种东西用上继承也没有意义;另外两种运算符本身其实是重载了Operator,一般不认为是继承。例子如下:

struct S
{
public:S(int num) : num(num) {};bool operator==(S s){return this->num == s.num;}private:int num;
};int main()
{S s1{1};S s2{1};cout << (s1 == s2) << endl;
}

这里重载了==运算符,使得两个结构体之间可以比较。因为这不是继承,因此也无需显式指出S必须继承了==,但是如果S没有重载==,那IDE依然会给出警告。

3


use std::ops;// 实现 fn multiply 方法
// 如上所述,`+` 需要 `T` 类型实现 `std::ops::Add` 特征
// 那么, `*` 运算符需要实现什么特征呢? 你可以在这里找到答案: https://doc.rust-lang.org/core/ops/
fn multiplyfn main() {assert_eq!(6, multiply(2u8, 3u8));assert_eq!(5.0, multiply(1.0, 5.0));println!("Success!")
}

注意两点:

  1. 两个操作数是相同的类型,所以要用一般的泛型声明,而不是特征的语法糖
  2. 别忘了写返回值
fn multiply<T: Mul<T, Output = T>>(n1: T, n2: T) -> T {n1 * n2
}

4


// 修复错误,不要修改 `main` 中的代码!
use std::ops;struct Foo;
struct Bar;struct FooBar;struct BarFoo;// 下面的代码实现了自定义类型的相加: Foo + Bar = FooBar
impl ops::Add<Bar> for Foo {type Output = FooBar;fn add(self, _rhs: Bar) -> FooBar {FooBar}
}impl ops::Sub<Foo> for Bar {type Output = BarFoo;fn sub(self, _rhs: Foo) -> BarFoo {BarFoo}
}fn main() {// 不要修改下面代码// 你需要为 FooBar 派生一些特征来让代码工作assert_eq!(Foo + Bar, FooBar);assert_eq!(Foo - Bar, BarFoo);println!("Success!")
}

这段代码缺少下面几个特征:

  1. FooBar之间的比较
  2. BarFoo之间的比较
  3. FooBar的减法
  4. 由于asser_eq需要debug打印,FooBarBarFoo也需要实现这个特征,但是只需要derive派生一下就行了。
#[derive(Debug)]
struct FooBar;#[derive(Debug)]
struct BarFoo;//...
impl PartialEq<FooBar> for FooBar{fn eq(&self, other: &FooBar) -> bool {true}
}impl PartialEq<BarFoo> for BarFoo{fn eq(&self, other: &BarFoo) -> bool {true}
}impl ops::Sub<Bar> for Foo {type Output = BarFoo;fn sub(self, rhs: Bar) -> Self::Output {BarFoo}
}

这代码的啰嗦程度堪比 Java ,但是说到底这种无意义的比较应该只存在练习题当中。

5


// 实现 `fn summary` 
// 修复错误且不要移除任何代码行
trait Summary {fn summarize(&self) -> String;
}#[derive(Debug)]
struct Post {title: String,author: String,content: String,
}impl Summary for Post {fn summarize(&self) -> String {format!("The author of post {} is {}", self.title, self.author)}
}#[derive(Debug)]
struct Weibo {username: String,content: String,
}impl Summary for Weibo {fn summarize(&self) -> String {format!("{} published a weibo {}", self.username, self.content)}
}fn main() {let post = Post {title: "Popular Rust".to_string(),author: "Sunface".to_string(),content: "Rust is awesome!".to_string(),};let weibo = Weibo {username: "sunface".to_string(),content: "Weibo seems to be worse than Tweet".to_string(),};summary(post);summary(weibo);println!("{:?}", post);println!("{:?}", weibo);
}// 在下面实现 `fn summary` 函数

直接调用特征的方法即可:

fn summary(porw: &impl Summary) -> String{porw.summarize()
}

哦对了,调用的地方需要改成借用,否则所有权转移后,后面打印不出来。

6


struct Sheep {}
struct Cow {}trait Animal {fn noise(&self) -> String;
}impl Animal for Sheep {fn noise(&self) -> String {"baaaaah!".to_string()}
}impl Animal for Cow {fn noise(&self) -> String {"moooooo!".to_string()}
}// 返回一个类型,该类型实现了 Animal 特征,但是我们并不能在编译期获知具体返回了哪个类型
// 修复这里的错误,你可以使用虚假的随机,也可以使用特征对象
fn random_animal(random_number: f64) -> impl Animal {if random_number < 0.5 {Sheep {}} else {Cow {}}
}fn main() {let random_number = 0.234;let animal = random_animal(random_number);println!("You've randomly chosen an animal, and it says {}", animal.noise());
}

我还没学习特征对象,所以我决定直接改成假的随机

fn random_animal(random_number: f64) -> impl Animal {if random_number < 0.5 {Sheep {}} else {Sheep {}}
}

7

fn main() {assert_eq!(sum(1, 2), 3);
}// 通过两种方法使用特征约束来实现 `fn sum`
fn sum<T>(x: T, y: T) -> T {x + y
}

我就能想出一种方法:

fn sum<T: Add<T, Output = T>>(x: T, y: T) -> T {x + y
}

8

// 修复代码中的错误
struct Pair<T> {x: T,y: T,
}impl<T> Pair<T> {fn new(x: T, y: T) -> Self {Self {x,y,}}
}impl<T: std::fmt::Debug + 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);}}
}struct Unit(i32);fn main() {let pair = Pair{x: Unit(1),y: Unit(3)};pair.cmp_display();
}

本质上是Unit没有实现特征,加上就好了

#[derive(Debug, PartialEq, PartialOrd)]
struct Unit(i32);

9


// 填空
fn example1() {// `T: Trait` 是最常使用的方式// `T: Fn(u32) -> u32` 说明 `T` 只能接收闭包类型的参数struct Cacher<T: Fn(u32) -> u32> {calculation: T,value: Option<u32>,}impl<T: Fn(u32) -> u32> Cacher<T> {fn new(calculation: T) -> Cacher<T> {Cacher {calculation,value: None,}}fn value(&mut self, arg: u32) -> u32 {match self.value {Some(v) => v,None => {let v = (self.calculation)(arg);self.value = Some(v);v},}}}let mut cacher = Cacher::new(|x| x+1);assert_eq!(cacher.value(10), __);assert_eq!(cacher.value(15), __);
}fn example2() {// 还可以使用 `where` 来约束 Tstruct Cacher<T>where T: Fn(u32) -> u32,{calculation: T,value: Option<u32>,}impl<T> Cacher<T>where T: Fn(u32) -> u32,{fn new(calculation: T) -> Cacher<T> {Cacher {calculation,value: None,}}fn value(&mut self, arg: u32) -> u32 {match self.value {Some(v) => v,None => {let v = (self.calculation)(arg);self.value = Some(v);v},}}}let mut cacher = Cacher::new(|x| x+1);assert_eq!(cacher.value(20), __);assert_eq!(cacher.value(25), __);
}fn main() {example1();example2();println!("Success!")
}

Cachervalue()实际上是,如果调用时Cacher没有value,就对value()的参数执行初始化时设定好的闭包;否则,就返回Cachervalue,无论参数的值是多少。

    assert_eq!(cacher.value(10), 11);assert_eq!(cacher.value(15), 11);
    assert_eq!(cacher.value(20), 21);assert_eq!(cacher.value(25), 21);

相关文章:

【Rust练习】18.特征 Trait

练习题来自&#xff1a;https://practice-zh.course.rs/generics-traits/traits.html 1 // 完成两个 impl 语句块 // 不要修改 main 中的代码 trait Hello {fn say_hi(&self) -> String {String::from("hi")}fn say_something(&self) -> String; }str…...

【自动化测试之oracle数据库】MacOs如何安装oracle- client

操作系统为Mac OS&#xff0c;本地在pycharm上跑自动化脚本时&#xff0c;因为有操作oracle数据库的部分&#xff0c;所以需要安装oracle数据库的客户端&#xff0c;并install cx_oracle,本文主要介绍如何在macOS上完成安装&#xff0c;并在python自动化测试代码中配置&#xf…...

Spring MVC的MultipartFile

定义 MultipartFile接口是Spring MVC中用来处理上传文件的接口&#xff0c;它提供了访问上传文件内容、文件名称、文件大小等信息的方法。 源码&#xff1a; package org.springframework.web.multipart;import java.io.File; import java.io.IOException; import java.io.I…...

●Leetcode| 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数● 1. 两数之和

242,该题目中数组范围比较短&#xff0c;可以数组使用并不会占太多的空间&#xff0c;利用数组的映射&#xff0c;查找到自己所需要的字符 class Solution { public:bool isAnagram(string s, string t) {int record[26] {0};for(int i0;i<s.size();i){record[s[i] - a];/…...

关于算法的时间复杂度和空间复杂度的分析

由于最近开始准备蓝桥杯(python组)&#xff0c;开始对编程基础进行一些复习&#xff0c;当我发现蓝桥对大多数题目程序运行时间及大小有要求时&#xff0c;我知道我不得不考虑性能问题&#xff0c;而不是能跑就行&#x1f913; 写下这篇文章希望对其他同志有帮助吧 什么是算法…...

深入浅出 C++ STL:解锁高效编程的秘密武器

引言 C 标准模板库&#xff08;STL&#xff09;是现代 C 的核心部分之一&#xff0c;为开发者提供了丰富的预定义数据结构和算法&#xff0c;极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C 开发者来说至关重要。以下是对 STL 的详细介绍&#xff0c;涵盖其基础知…...

2024年1024程序人生总结

2024-1024 0.大环境0.1.经济0.2.战争 1.我的程序人生1.1.游戏 2.节日祝福 0.大环境 今年的1024最大的感触就是没有节日氛围&#xff0c;往年公司还会准备节日礼物&#xff0c;今年没有&#xff0c;由此可见大环境有多么糟糕。 除此之外&#xff0c;就是到公司应聘的程序员越来…...

【p2p、分布式,区块链笔记 分布式容错算法】: 拜占庭将军问题+实用拜占庭容错算法PBFT

papercodehttps://pmg.csail.mit.edu/papers/osdi99.pdfhttps://github.com/luckydonald/pbft 其他相关实现&#xff1a;This is an implementation of the Pracltical Byzantine Fault Tolerance protocol using PythonAn implementation of the PBFT consensus algorithm us…...

鸿蒙NEXT开发-应用数据持久化之用户首选项(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…...

人工智能_神经网络103_感知机_感知机工作原理_感知机具备学习能力_在学习过程中自我调整权重_优化效果_多元线性回归_逻辑回归---人工智能工作笔记0228

由于之前一直对神经网络不是特别清楚,尤其是对神经网络中的一些具体的概念,包括循环,神经网络卷积神经网络以及他们具体的作用,都是应用于什么方向不是特别清楚,所以现在我们来做教程来具体明确一下。 当然在机器学习之后还有深度学习,然后在深度学习中对各种神经网络的…...

WISE:重新思考大语言模型的终身模型编辑与知识记忆机制

论文地址&#xff1a;https://arxiv.org/abs/2405.14768https://arxiv.org/abs/2405.14768 1. 概述 随着世界知识的不断变化&#xff0c;大语言模型&#xff08;LLMs&#xff09;需要及时更新&#xff0c;纠正其生成的虚假信息或错误响应。这种持续的知识更新被称为终身模型编…...

网络安全证书介绍

网络安全领域有很多专业的证书&#xff0c;可以帮助你提升知识和技能&#xff0c;增强在这个行业中的竞争力。以下是一些常见的网络安全证书&#xff1a; 1. CompTIA Security 适合人群&#xff1a;初级安全专业人员证书内容&#xff1a;基础的网络安全概念和实践&#xff0c…...

【已解决】【hadoop】【hive】启动不成功 报错 无法与MySQL服务器建立连接 Hive连接到MetaStore失败 无法进入交互式执行环境

启动hive显示什么才是成功 当你成功启动Hive时&#xff0c;通常会看到一系列的日志信息输出到控制台&#xff0c;这些信息包括了Hive服务初始化的过程以及它与Metastore服务连接的情况等。一旦Hive完成启动并准备就绪&#xff0c;你将看到提示符&#xff08;如 hive> &#…...

基于架设一台NFS服务器实操作业

架设一台NFS服务器&#xff0c;并按照以下要求配置 首先需要关闭防火墙和SELinux 1、开放/nfs/shared目录&#xff0c;供所有用户查询资料 赋予所有用户只读的权限&#xff0c;sync将数据同步写到磁盘上 在客户端需要创建挂载点&#xff0c;把服务端共享的文件系统挂载到所创建…...

eachers中的树形图在点击其中某个子节点时关闭其他同级子节点

答案在代码末尾&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; tubiaoinit(params: any) {// 手动触发变化检测this.changeDetectorRef.detectChanges();if (this.myChart ! undefined) {this.myChart.dispose();}this.myChart echarts.init(this.pieChart?…...

Maven 介绍与核心概念解析

目录 1. pom文件解析 2. Maven坐标 3. Maven依赖范围 4. Maven 依赖传递与冲突解决 Maven&#xff0c;作为一个广泛应用于 Java 平台的自动化构建和依赖管理工具&#xff0c;其强大功能和易用性使得它在开发社区中备受青睐。本文将详细解析 Maven 的几个核心概念&a…...

计算机网络-MSTP概述

一、RSTP/STP的缺陷与不足 前面我们学习了RSTP对于STP的一些优化与快速收敛机制。但在划分VLAN的网络中运行RSTP/STP&#xff0c;局域网内所有的VLAN共享一棵生成树&#xff0c;被阻塞后的链路将不承载任何流量&#xff0c;无法在VLAN间实现数据流量的负载均衡&#xff0c;导致…...

Redisson(三)应用场景及demo

一、基本的存储与查询 分布式环境下&#xff0c;为了方便多个进程之间的数据共享&#xff0c;可以使用RedissonClient的分布式集合类型&#xff0c;如List、Set、SortedSet等。 1、demo <parent><groupId>org.springframework.boot</groupId><artifact…...

考研要求掌握的C语言程度(堆排序)1

含义 堆排序就是把数组的内容在心中建立为大根堆&#xff0c;然后每次循环把根顶和没交换过的根末进行调换&#xff0c;再次建立大根堆的过程 建树的几个公式 一个数组有n个元素 最后一个父亲节点是n/2-1; 假如父亲节点在数组的下标为a 那么左孩子节点在数组下标为2*a1,…...

chronyd配置了local的NTP server之后, NTP报文中出现public IP的问题

描述 客户在Rocky Linux 9.4的VM上配了一个local的NTP server(IP: 10.64.1.76)。 配置完成后, 时钟可以同步&#xff0c;但一段时间后客户的firewall收到告警, 拒绝了大量目标端口为123的请求, 且这些请求的目的IP并不是客户指定的NTP server的IP&#xff0c;客户要求解释原因…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...