看一看Rust,记录笔记:类型系统

2023-05-16

文章目录

  • 第五章:类型系统
    • 泛型
      • 泛型与容器
      • 泛型与结构体
      • 泛型与枚举
      • 泛型与函数
      • 泛型与方法
    • trait系统
      • trait 定义与实现
      • trait 作为参数
        • impl Trait
        • trait 约束
      • 返回实现trait 的类型
      • 标准版常用trait
        • 格式化输出Debug 和Display
        • 等值比较Eq与PartialEq
        • 次序比较Ord 与 PartialOrd
        • 复制值 Clone 与 Copy
        • 默认值Default
      • 类型转换
        • 原生类型间的转换
        • 数字与String 类型间的转换
        • &str 与 String 类型间转换

第五章:类型系统

Rust 是一门强类型且类型安全的静态语言,Rust 中一切皆类型,包括基本的原生类型和复合类型。

这里重点介绍 泛型 和 trait 系统

泛型

泛型是指在运行时指定数据类型的机制,优势是可以编写更为抽象和通用的代码,减少重复的工作量

表示为 泛型,,

泛型与容器

fn main() {
    let mut vec_integer: Vec<i32> = vec![1,2];
    vec_integer.push(3);
}

泛型与结构体

泛型类型的结构体是指结构体的字段类型是泛型类型,他可以拥有一个或多个泛型类型。

struct Rectangle1<T> {
    width: T,
    height: T,
}

struct Rectangle2<T, U> {
    width: T,
    height: U,
}

impl<T> Rectangle1<T> {
    fn width(&self) -> &T {
        &self.width
    }
    fn height(&self) -> &T {
        &self.height
    }
}

impl Rectangle1<i32> {
    fn area(&self) -> i32 {
        self.width * self.height
    }
}


impl<T, U>  Rectangle2<T, U> {
    fn width(&self) -> &T {
        &self.width
    }

    fn height(&self) -> &U {
        &self.height
    }
}

fn main() {
    let rect1 = Rectangle1 { width: 8, height: 2 };
    println!("rect1.width: {}", rect1.height);

    println!(rect1.area());


    let rect2 = Rectangle2 { width: 8, height: 2.2 };
    print!(rect2.width);
}

泛型与枚举

泛型枚举是指枚举值类型是泛型类型。标准库提供的Option 就是一个应用广泛的泛型枚举

enum Option<T>{
    Some(T),
    None,
}

Option<T> 表示可能有值,也可能无值这一抽象概念,

Some 表示可能的值可以使任意类型T,

None 表示不存在Option类型会被Rust自动引入,不需要再显示引用

fn option_add(x: Option<i32>, y: Option<i32>) -> Option<i32> {
    return if x.is_none() && y.is_none() { None } else if x.is_none() { y } else if y.is_none() { x } else {
        Some(x.unwrap() + y.unwrap()) // 如果值为None, 不能使用unwrap
    };
}

泛型与函数

函数的参数和返回值都可以是泛型类型,带有泛型类型的参数或返回值的函数叫做泛型函数。

fn foo<T>(x: T) -> T {
    return x;
}

fn main() {
    println!("{}", foo(4));
    println!("{}", foo("hello"))
}

泛型与方法

带有泛型类型的参数或返回值的方法叫作泛型方法

需要在impl后面跟着<T> 才可以在方法的参数或返回值使用泛型

impl<T> Rectange1<T>{
	fn width(&self) -> &T{
    	&self.width
    }
}

trait系统

Rust 中没有 接口这样的概念。trait 是 唯一的接口抽象方式,用于跨多个结构体以一种抽象的方式定义共享的行为(方法),即 trait 可以让不同的结构体实现相同的行为。

trait 定义与实现

trait 的本质 是一组方法原理,是实现某些目的的定位集合。

trait Geometry{
	fn area(&self)-> f32;
    fn perimeter(&sefl)->f32;
}

从语法来说,trait 可以包含两种形式的方法: 抽象方法和具体方法。

trait Geometry {
    fn area(&self) -> f32;
    fn perimeter(&self) -> f32;
}

struct Rectangle {
    width: f32,
    height: f32,
}

impl Geometry for Rectangle {
    fn area(&self) -> f32 {
        self.width * self.height
    }

    fn perimeter(&self) -> f32 {
        (self.width + self.height) * 2
    }
}

struct Circle {
    radius: f32,
}

impl Geometry for Circle {
    fn area(&self) -> f32 {
        3.14 * self.radius * self.radius
    }

    fn perimeter(&self) -> f32 {
        3.14 * 2.0 * self.radius
    }
}

fn main() {
    let rect = Rectangle { width: 10.0, height: 20.0 };
    println!("rect : area :{}", rect.area())
}

trait 作为参数

trait 作为参数的两种常用方式:

  1. 使用impl Trait 语法表示参数类型
  2. 使用trait 对泛型参数进行约束

impl Trait

// 这里没有实现Geometry trait ,在调用print 函数,如果向其传递String或者i32 会报错 

fn print(geometry: impl Geometry) {
    println!("area : {}", geometry.area());
}

fn main() {
    let rect = Rectangle { width: 10.0, height: 20.0 };
    println!(rect)
}

下面是实现了Geometry trait 和 Display trait

use std::fmt::{Display, Formatter, Result};

impl Dispaly for Rectangle {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "Rectangle:({},{})", self.width, self.height)
    }
}

fn print1(geometry: impl Geometry + Display) {   // 表示同时实现 两种trait
    println!("{},area:{}", geometry, geometry.area())
}

fn main() {
    let rect = Rectangle { width: 10.0, height: 5.4 };
    println!(rect)
}

impl 还支持多个参数指定类型,

fn area_add(geo1: impl Geometray,geo2:impl Geometry){
	println!("{}",geo1)
}

trait 约束

约束是指使用trait 对泛型进行约束。

语法是:

fn generic<T:MyTrait + MyOtherTrait + SomeStandarTrait>(t:T){}

impl Display for Circle {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "Circle:({})", self.radius)
    }
}

fn print2<T: Geometry + Display>(geometry: T) {
    println!("{},area : {}", geometry, geometry.area())
}

fn main() {
    let circle = Circle { radius: 3.0 };
    print2(circle)
}

这里跟impl trait 相似的是,也是可以有多个trait 约束,

fn area_add<T:Geometry+Display +Clone,U:Geometry+Display+Debug>(geo1:T,geo2:U){}

在上述过于长的约束,会导致函数签名阅读性变差,,

fn area_add<T,U> (geo1:T,geo2:U) where T: Geometry+Display+Clone,U:Geometry+Dispaly+Debug{}

返回实现trait 的类型

函数的返回值类型也可以使用impl Trait 语法,返回某个实现了trait 的类型,

fn return_geomery() -> impl Geometry{
	Rectangle{
    	width:12.5,
        height: 5.5,
    }
}

标准版常用trait

trait 可以应用于填结构体或枚举定义的derive属性中

例如: 对于#[derive]语法标记的类型,编译器会自动为其生成对应trait的默认实现代码。

格式化输出Debug 和Display

Debug trait 可以开启格式化字符串中的调试格式,常用于调试上下文中以{:?}{:#?}格式打印输出一个类型的实例。

Display trait 是以{}格式打印输出信息的,主要用于面向用户的输出。但是Display不能与derive 属性一起使用。

要实现Display 必须实现fmt方法

// 打印类型实例
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Display for Point {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "({},{})", self.x, self.y)
    }
}

fn main() {
    let origin = Point { x: 0, y: 0 };
    println!("{}", origin);
    println!("{:?}", origin);
    println!("{:#}", origin)
}

(0,0)
Point (x:0,y:0)
Point {
	x:0,
    y:0
}

等值比较Eq与PartialEq

Eq 和 Partial 都是来自数学的等价关系和局部等价关系。两者都满足以下两个特性:

  1. 对称性,即 a==b 可推导出 b == a
  2. 传递性 , 即 a ==b 且 b c 可推导出 a c
  3. eq 特殊: 反身性 : 即 a== a
  4. 浮点数类型,两个非数字值 ,特殊 NaN != NaN>

PartialEq 可以通过判断结构体的参数是否相等,来判断实例是否相等。(这里书中并没有说地址,而是实例里面的字段)

enum BookFormat {
    Paperback,
    // Hardback,
    Ebook,
}
// 新版rust 不再容许创建,而不使用的情况
#[allow(dead_code)]
struct Book {
    isbn: i32,
    format: BookFormat,
}

impl PartialEq for Book {
    fn eq(&self, other: &Self) -> bool {
        self.isbn == other.isbn
    }
}


fn main() {
    let b1 = Book { isbn: 3, format: BookFormat::Paperback };
    let b2 = Book { isbn: 3, format: BookFormat::Ebook };
    let b3 = Book { isbn: 5, format: BookFormat::Paperback };


    assert!(b1 == b2);
    assert!(b1 != b3);
}

次序比较Ord 与 PartialOrd

Ord 时表示 全序关系的trait ,全序关系 是指集合中任何一对元素都是相互可比较。以下特性:

  1. 完成反对称,即任何一对元素之间的关系只能是a<b, a == b 或 a > b 中的其中一种
  2. 传递性,即 a < b 且 b < c 可推导出 a <c , “==” 和 > 同理。

partialOrd 基于排序目的对类型实例进行比较的,可以直接使用 <,>,<= 和 >= 运算符进行比较。特性:

  1. 反对称性 a <b 则 !(a > b) ,反之亦然
  2. 传递性, 即 a <b 且 b < c 可推导出 a < c , == , > 同理

两者都要求能进行元素是否相等的比较,因此对Eq 和 PartialEq 有以下依赖要求:

  1. PartialOrd 要求类型实现 PartialEq
  2. Ord 要求类型实现 partialOrd 和 Eq

复制值 Clone 与 Copy

这里涉及 栈内存 和堆内存 ,按位复制和深复制以及引用概念

Clone trait 用于标记 可以对值进行深复制的类型,即对栈上和堆上的数据一起复制。

实现CLone,需要实现clone方法。如果使用 trait -》 #[derive(Clone)] 标记结构或者枚举,必须要求结构体每个字段或枚举都可调用clone 方法。换句话说 都要必须实现Clone 。

Copy trait 用于标记 按位复制其值的类型,即复制栈上的数据。且必须实现Clone 的 clone 方法。简化方法->

#[derive(Copy,Clone)]

等于

impl Copy for mystruct {}

impl Clone for myStruct {

​ fn clone () …

}

Copy 是一个隐式行为,开发者不能重载Copy 行为,就是一个简单的位复制。

常发生 在 执行变量绑定,函数参数传递,函数返回的场景中。

默认值Default

Default trait 为类型提供有用的默认值,通常用于结构体的字段提供默认值。如果每个字段都实现了Default ,那么Default 可以与 derive 属性一起使用,对每个字段都用默认值


#[derive(Default, Debug)]
struct MyStruct {
    foo: i32,
    bar: f32,
}


fn main() {
    let options1: MyStruct = Default::default();

    println!("options: {:?}", options1)
}

类型转换

类型转换 分为隐式转换 和显示类型转换 。

隐式类型转换有编译器来完成的

显示类型是有开发者来指定的。

原生类型间的转换

as 关键字 用于rust 中 原生数据类型间的转换,需要注意的是 , 短类型转换为长类型是没有的,但是长类型转换为短类型会被截断处理。有无符号,也不适合as关键字

这个与每个语言都这相似的规则

fn main() {
    let x: u16 = 7;
    let y = x as u32;
    println!("u16 : {}, u32 : {}", x, y);
    
    
    
}

数字与String 类型间的转换

使用to_string 方法可以将任意数字转换为String 类型,使用 parse 方法可以将 String 类型解析为指定的数字类型

  let x = 7;
    let y = x.to_string();

    let x1 = String::from("8");
    let y1 = x1.parse::<f64>().unwrap();

&str 与 String 类型间转换

  1. 使用 as_str 方法可以将 String 类型转换为&str 类型
  2. 使用to_string 方法可以将 &str 转换为String 类型
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

看一看Rust,记录笔记:类型系统 的相关文章

  • win10如何退出“暂停7天更新”? 恢复自动更新

    services msc 微软社区的解答 xff0c 我复bai制的 断开网络进du行如下操作 xff0c 如果遇到zhi程序占用的问题 xff0c 操作进入到dao安全模式 xff08 设置 更新和安全 恢复 立即重启 xff09 进行
  • 关于Qt中线程的挂起和唤醒问题

    为了平台的可移植性 xff0c 现在好多公司或开发者都在用Qt开发 xff0c 但是Qt开发文档有一个不非常理想的问题是 xff0c 有些问题描述的不是太详细 xff0c 特别是涉及到线程的挂起 xff0c 唤醒 和sleep 等问题 在Q
  • vscode不能跳转到定义的解决方法

    vscode不能跳转到定义的解决方法 0 分析1 安装global的依赖2 安装global3 安装插件并生成索引文件 0 分析 在Linux上使用vscode时发现跳转到定义非常缓慢 xff0c 甚至不能用 打开扩展C 43 43 Int
  • UI----UIslider 和UIcontrol的属性

    UISlide 属性 minimumValue 当值可以改变时 xff0c 滑块可以滑动到最小位置的值 xff0c 默认为 0 0 slider minimumValue 61 10 0 maximumValue 当值可以改变时 xff0c
  • JAVA转义字符详解

    一 JAVA中反斜杠 的作用 在不同的系统中 xff0c 路径的分隔符不同 xff0c 故需要做出判断 xff0c 并切换分隔符 VBS代码中确实不用转义 xff0c 但是在JAVA或JS中 xff0c 它采用的是C语言的语法 xff0c
  • 枚举(enum)

    一 什么是枚举 我们学习过单例模式 xff0c 即一个类只有一个实例 而枚举其实就是多例 xff0c 一个类有多个实例 xff0c 但实例的个数不是无穷的 xff0c 是有限个数的 例如word文档的对齐方式有几种 xff1a 左对齐 居中
  • 安卓so包常见报错问题

    一 lib arm64 system lib64 vendor lib64 couldn 39 t find 34 libAndroidIDCard so 我没有在libs文件夹下面创建类似 arm64 v8a 这个文件夹 xff0c 因为
  • Ubuntu详解

    介绍 Ubuntu是一个以桌面应用为主的Linux操作系统 xff0c 其名称来自非洲南部祖鲁语或豪萨语的 ubuntu 34 一词 xff0c 意思是 人性 我的存在是因为大家的存在 34 xff0c 是非洲传统的一种价值观 Ubuntu
  • Selinux详解

    一 介绍 1 1百度百科 SELinux Security Enhanced Linux 是美国国家安全局 xff08 NSA xff09 对于强制访问控制的实现 xff0c 是 Linux历史上最杰出的新安全子系统 NSA是在Linux社
  • repo init详解

    首先选择manifest源 xff0c 一般直接使用清华或中科大的镜像源 repo init u https aosp tuna tsinghua edu cn platform manifest是清华提供的镜像源 repo init u
  • Android Gradle plugin requires Java 11 to run.

    报错分析 因为别人拷过来的项目gradle版本不同 xff0c 对于jdk的兼容性要求不同 之前调试什么东西 xff0c 不小心改了环境的的某个部分 xff0c 现在莫名其妙所有的项目都运行不了了 后来百度翻译了一下 xff0c Andro
  • 安卓稳定性技术栈

    涉及技术内容 xff1a framework java层 语言 xff1a Java 1 开机启动流程 xff1a Android 7 0平台开机启动 android7 0开机自启 jamousjang的博客 CSDN博客 Android系
  • keil在线调试STM32,点三次运行才能跑到main的问题解决。

    现象 使用keil开发STM32 xff0c 下载完程序后 xff0c 不能运行 在main 的入口处加打印 xff0c 啥也没打出来 xff0c 说明程序都没跑到main 在线调试debug时发现了个有意思的现象 xff0c 每次都是点击
  • JAVA中“...”三个点

    可变长参数 xff0c 就是这个位置可以传入任意个该类型参数 简单来说就是个数组 1 testPoints 7 2 testPoints 7 9 11 3 testPoints new Integer 7 9 11 1 public sta
  • IMSI,SN,IMEI分别是什么意思

    1 IMSI 国际移动用户识别码 xff08 IMSI xff1a International Mobile Subscriber Identification Number xff09 是区别 移动用户 的标志 xff0c 储存在 SIM
  • Glide详解

    现在Android上的图片加载框架非常成熟 xff0c 从最早的老牌图片加载框架UniversalImageLoader xff0c 到后来Google推出的Volley xff0c 再到后来的新兴军Glide和Picasso xff0c
  • ubuntu软件包系统已损坏

    多半是上次更新没有更新完 span class hljs built in sudo span apt get clean 说明 删除包缓存中的所有包 将 var cache apt archives 的 所有 deb 删掉 span cl
  • 机器学习及深度学习中的符号说明

    文章目录 数和数组集合和图索引线性代数中的操作微积分概率和信息论函数数据集和分布 数和数组 a a a 标
  • 51单片机系列外部中断(附源码)

    要求 用STC89C51单片机 xff0c 按键 xff0c LED灯完成外部中断实验 程序中点亮LED流水灯 xff0c 当按键按下时 xff0c 外部中断触发 xff0c 程序转至中断服务程序 xff0c 在中断服务程序中使LED灯全亮
  • Linux执行Jar包出现ClassNotFound、“main”找不到主类

    在Linux虚拟机系统执行jar包的过程中 xff0c 经常会出现类似ClassNotFound等类似的错误 xff0c 无法完成jar包的运行 xff0c 根据经验 xff0c 总结几点如下 xff0c 便于自己记忆 xff0c 后期查看

随机推荐

  • Linux中文乱码问题终极解决方法

    方法一 xff1a 修改 root bash profile文件 xff0c 增加export LANG 61 zh CN GB18030 该文件在用户目录下 xff0c 对于其他用户 xff0c 也必须相应修改该文件 使用该方法时putt
  • CentOS7

    Konsole使用方法 root用户 su su root 打开文件修改文件 按 i 编辑 xff0c esc退出编辑 xff0c 然后 wq 保存退出 vi etc selinux config 桌面环境 yum y groups ins
  • 【模拟测试题】

    B题 题意 xff1a 在另一个位面 xff0c 世界末日发生了 东东作为诺亚方舟的船长 xff0c 他现在从月球开始启动诺亚方舟去其他星球营救民众 东东从若干星球将人运回大本营 xff0c 星球的数目以及每个星球的坐标和人数都将由输入决定
  • 解决Qt Qml应用使用windeployqt部署后仍不能运行的问题

    问题描述 在Windows系统中官方推荐使用windeployqt xff0c 使用C 43 43 开发的应用程序使用windeployqt很好用 xff0c 但是使用Qml开发的应用却不能运行 xff0c 双击之后一点反应也没有 解决方法
  • 模拟题【Week15实验】

    A题 题意 xff1a Q 老师有 N 个学生 xff0c 每个学生都有各自独立的编号 xff0c 且编号范围在 1 N 之间 这一天 xff0c 所有学生都在不同的时间进入教室 Q 老师记录了当编号为 i 的学生进入教室时 xff0c 教
  • 代码Bug太多?给新人Code Review头都大了?快来试试SpotBugs

    如果你需要一个自动化的工具帮助你或者你的团队发现代码中的缺陷 xff0c 在提升代码质量同时减少人工Code Review的成本 xff0c 那这篇文章非常的适合你 本文围绕SpotBugs与Gradle集成 xff0c 将相关配置和使用进
  • Ubuntu 16.04.1配置远程连接(xrdp)

    本文主要介绍如何在windows下连接Ubuntu 16 04 1系统 一 系统信息 1 win7 xff0c win8 xff0c win10均可 xff0c 但需要确认系统为专业版或企业版 xff0c 家庭版无法远程连接Ubuntu系统
  • 刚毕业的表弟年薪40w......程序员薪资天花板?

    前不久 xff0c 腾讯2022校招 应届毕业生年薪 40 万 刷屏了 尽管互联网大厂的薪资高不算什么新鲜事儿 xff0c 但这个热搜仍然让我大受震撼 腾讯校招官网显示 xff0c 2022届腾讯校招开放技术 产品 设计等岗位共计 78 个
  • MySQL5.7安装与配置(YUM)

    原文链接 xff1a http blog csdn net xyang81 article details 51759200 安装环境 xff1a CentOS7 64位 xff0c MySQL5 7 1 配置YUM源 在MySQL官网中下
  • ACM竞赛入门,从零开始

    前言 ACM竞赛其实可以在编程初级阶段边学边练 xff0c 门槛没有比想象中高那么多 xff0c 如果实在不会做也可以直接在网上搜题分析答案 xff0c 弄懂后自己再亲手写出来 xff0c 当然你需要懂得基本的语义 语法 xff0c 保证看
  • matlab寻找函数对应的工具箱

    官方文档说函数对应的工具箱就在函数的介绍页面上方 xff0c 一开始没看懂什么意思 xff0c 后面知道怎么看了 红色方框内的即使函数所在工具箱的信息 例如这个finv函数就在Statistics and Machine Learning工
  • Collecting package metadata (current_repodata.json): done Solving environment: failed with repodata

    用 conda create name test python 61 3 4创建 python3 4 版本的 test环境报错 xff0c 然后在指定位置创建了一个文件 注意到这句话 xff0c 没有找到包 xff0c 换命令为 conda
  • navicat创建数据库后显示图标灰色,右键后无法新建数据库

    双击你的连接即可
  • unity_导出场景、包

    会发现以场景为单位的各种依赖都包括进来了
  • vscode + gdbserver 实现交叉调试

    0 前言 鉴于以下的痛点 xff0c 尝试了一下gdbserver配合vscode xff0c 发现十分好用 应用程序比较大 xff0c 依赖的库也很多 xff0c 设备上没有足够的存储空间 设备没有预留显示接口 在终端里面放断点调试效率低
  • Ubuntu14.04/Linux安装LLVM/clang-3.7(带有标准库 libc++,libc++abi)

    参考文章 https github com yangyangwithgnu use vim as ide 7 1 1 http blog csdn net firebird321 article details 48528569 一 不需源
  • 1.1小程序内置tabbar和自定义tabbar区别

    文章目录 内置tabbar自定义 tabbar创建文件夹 custom tab bar发现小程序自定义tabBar切换颜色总是比点击慢一步switchtab报错 switchTab fail page pages home pages me
  • 无基础小白 js 快速入门1.1

    文章目录 js的运行方法1js的运行方法2如何编写js代码如何运行js文件调试基本语法不一定用 结尾语句块注释 数据类型和变量Number字符串布尔值比较运算符null 和 undefined数组对象变量 区分动态语言和静态语言 js的运行
  • STM32F103寄存器方式点亮LED流水灯

    STM32F103寄存器方式点亮LED流水灯 一 程序设计思路1 GPIO 模式2 控制引脚输出电平3 开启外设时钟 二 编程实现1 C语言2 汇编语言3 实现 三 总结四 参考 以 STM32最小系统核心板 STM32F103C8T6 4
  • 看一看Rust,记录笔记:类型系统

    文章目录 第五章 xff1a 类型系统泛型泛型与容器泛型与结构体泛型与枚举泛型与函数泛型与方法 trait系统trait 定义与实现trait 作为参数impl Traittrait 约束 返回实现trait 的类型标准版常用trait格式