【Rust 学习笔记】Rust 基础数据类型介绍(一)

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持!
博主链接

博客内容主要围绕:

5G/6G协议讲解

高级C语言讲解

Rust语言讲解

文章目录

  • [Rust 基础数据类型介绍(一)](#Rust 基础数据类型介绍(一))
    • 一、固定宽度的数值类型
      • [1.1 整型](#1.1 整型)
        • [1.1.1 无符号整型](#1.1.1 无符号整型)
        • [1.1.2 有符号整型](#1.1.2 有符号整型)
        • [1.1.3 整型字面量](#1.1.3 整型字面量)
        • [1.1.4 字节字面量](#1.1.4 字节字面量)
      • [1.2 浮点类型](#1.2 浮点类型)
      • [1.3 转换运算符](#1.3 转换运算符)
      • [1.4 检查算法、回绕算法、饱和算法和溢出算法](#1.4 检查算法、回绕算法、饱和算法和溢出算法)
        • [1.4.1 检查运算](#1.4.1 检查运算)
        • [1.4.2 回绕运算](#1.4.2 回绕运算)
        • [1.4.3 饱和运算](#1.4.3 饱和运算)
        • [1.4.4 溢出运算](#1.4.4 溢出运算)

Rust 基础数据类型介绍(一)

Rust中的数据类型如下所示,我会分多篇博客来介绍,下面先看一个总览:

类型 简要说明
i8、i16、i32、i64、i128、u8、u16、u32、u64、u128 给定位宽的有符号整数和无符号整数
isize、usize 与机器字(32bit、64bit)一样大的有符号整数和无符号整数
f32、f64 单精度IEEE浮点数和双精度IEEE浮点数
bool 布尔值
char Unicode字符,32位宽(4字节)
() 单元元组(空元组)
(char,u8,i32) 元组(允许混合类型)
Box<Attend> 指向堆中值的拥有型指针
&i32、&mut i32 共享引用和可变引用,非拥有型指针,其生命周期不能超出引用目标
String UTF-8字符串,动态分配大小
&str 对str的引用,指向UTF-8文本的非拥有型指针
[f64;4]、[u8;256] 数组,固定长度,其元素类型都相同
Vec[f64] 向量,可变长度,其元素类型都相同
&[u8]、*mut [u8] 对切片(数组或向量某一部分)的引用,包含指针和长度
Option<&str> 可选值,或为None(无值),或者为Some(v)(有值,其值为v)
Result<u64, Error> 可能失败的操作结果,或者为成功值OK(v),或者为错误值Err(e)
struct S { x: f32, y: f32 } 具名字段型结构体
struct T(i32, char); 元组型结构体
struct E; 单元型结构体,无字段
enum Attend { OnTime, Late(u32)} 枚举,或代数数据类型
&dyn Any、&mut dyn Read 特型(trait)对象,是对任何实现了一组给定方法的值的引用
fn(&str)->bool 函数指针
(闭包类型没有显式书写形式) 闭包

一、固定宽度的数值类型

Rust中数值类型的名称都遵循一种统一的模式,也就是位数表面它的宽度,以前缀表明它的用法,如下图所示:

位宽 无符号整数 有符号整数 浮点数
8 u8 i8
16 u16 i16
32 u32 i32 f32
64 u64 i64 f64
128 u128 i128
机器字 usize isize

1.1 整型

1.1.1 无符号整型

Rust 的无符号整型会使用它们的完整范围来表示正值和 0,如下表所示:

类型 范围
u8 0~28-1(0~255)
u16 0~216-1(0~65535)
u32 0~232-1(0~4 294 967 295)
u64 0~264-1(0~18 446 744 073 709 551 615)
u128 0~2128-1(0~255)
usize 0~232-1 或 0~264-1
1.1.2 有符号整型

Rust 的有符号整型会使用二进制补码表示,使用与相应的无符号类型相同的位模式来覆盖正值和负值的范围,如下表所示:

类型 范围
i8 -27 ~ 27-1(-128 ~ 127)
i16 -215 ~ 215-1(-32768 ~ 32767)
i32 -231 ~ 231-1(-2 147 483 648 ~ 2 147 483 647)
i64 -263 ~ 263-1
i128 -2127 ~ 21278-1(0~255)
isize -231 ~ 231-1 或 -263 ~ 263-1

Rust会将u8类型作为字节值。例如,从二进制文件或套接字中读取数据时会产生一个 u8 值构成的流。usize类型和isize类型类似于C和C++中的size_tptrdiff_t,他们的精度与目标机器上地址空间的大小一致,即在32位架构上是32位长,在64位架构上是64位长。Rust要求数组索引是usize值,用来表示数组或向量大小或数据结构中元素数量的值通常也是usize类型

1.1.3 整型字面量

Rust中的整型字面量可以带上一个后缀来指示它的类型,例如,65u8是 u8类型。如果整型字面量没有携带类型后缀,Rust会延迟确定其类型,如果有多个候选类型,且包含i32,则选择 i32,否则报告类型歧义错误。

前缀 0x0o0b 分别表示十六进制字面量、八进制字面量和二进制字面量。为了易读性,可以在数字之间任意插入下划线,例如,4_294_967_295。下划线的具体位置无关紧要,因此也可以将十六进制数或二进制数按 4 位数字而非 3 位数字进行分组(如 0xffff_ffff),或分隔开数字的类型后缀(如 127_u8)。

字面量 类型 十进制数值
116i8 i8 116
0xcafeu32 u32 51966
0b0010_1010 推断 42
0o106 推断 70

下面是一个很有趣的问题,当我们运行

rust 复制代码
println!("{}", (-4).abs());

Rust编译器会报错,提示无法确定数据类型:

通常情况下是不需要指明数据类型的,Rust会自行推断,但是上面的例子中没有什么方法可用于推测 -4 的类型,因此我们需要显示的告诉Rust,例如下面的代码:

rust 复制代码
println!("{}", (-4_i32).abs());
println!("{}", i32::abs(-4));

另外需要注意,因为.运算符的优先级高于一元前缀运算符,所以需要在 -4 周围添加括号!

1.1.4 字节字面量

Rust为 u8 类型提供了字节字面量,例如,b'x' 表示以字符 x 的ASCII码作为 u8的值。需要注意的是只有ASCII字符才能出现在字节字面量中。下面几个字符是需要使用转义字符来表示的:

字符 字节字面量 等效数值
单引号(') b''' 39u8
反斜杠(\) b'\' 92u8
换行(lf) b'\n' 10u8
回车(cr) b'\r' 13u8
制表符(tab) b'\t' 9u8

1.2 浮点类型

Rust 提供了 IEEE 单精度浮点类型和 IEEE 双精度浮点类型。这些类型包括正无穷大和负无穷大、不同的正零值和负零值,以及非数值。如下表所示:

类型 精度 范围
f32 IEEE单精度(至少6位小数) 大约 -3.4x1038 ~ +3.4x1038
f64 IEEE双精度(至少15位小数) 大约 -1.8x10308 ~ +1.8x10308

Rust 的 f32 和 f64 分别对应于 C 和 C++(在支持 IEEE 浮点的实现中)以及 Java(始终使用 IEEE 浮点)中的 float 类型和 double 类型。

如果浮点字面量缺少类型后缀,那么Rust会检查上下文以查看值的使用方式,如果发现两种浮点类型都合适,就会默认选择f64

1.3 转换运算符

可以使用as运算符将一种整型类型转换为另一种整型类型。例如,

rust 复制代码
assert_eq!(   10_i8  as u16,    10_u16); // 范围内转换
assert_eq!( 2525_u16 as i16,  2525_i16); // 范围内转换

assert_eq!(   -1_i16 as i32,    -1_i32); // 带符号扩展
assert_eq!(65535_u16 as i32, 65535_i32); // 填零扩展

// 超出目标范围的转换生成的值等于原始值对2N取模的值,
// 其中N是按位算的目标宽度。有时这也称为"截断"
assert_eq!( 1000_i16 as  u8,   232_u8);
assert_eq!(65535_u32 as i16,    -1_i16);

assert_eq!(   -1_i8  as u8,    255_u8);
assert_eq!(  255_u8  as i8,     -1_i8);

1.4 检查算法、回绕算法、饱和算法和溢出算法

当整型算术运算溢出时,Rust在调试构建中会出现 panic。而在发布构建中,运算会回绕,即它生成的值等于"数学意义上正确的结果"对"值类型范围"取模的值(在任何情况下不会出现像C和C++中那样出现"溢出未定义"的行为)。

如果这种默认行为不是你想要的,则整型提供的某些方法可以让你准确地阐明自己期望的行为。

1.4.1 检查运算

检查运算会返回结果的Option 值:如果数学意义上正确的结果可以表示为该类型的值,那么就为 Some(v),否则为 None。

rust 复制代码
// 10与20之和可以表示为u8
assert_eq!(10_u8.checked_add(20), Some(30));

// 很遗憾,100与200之和不能表示为u8
assert_eq!(100_u8.checked_add(200), None);

// 做加法。如果溢出,则会出现panic
let sum = x.checked_add(y).unwrap();

// 奇怪的是,在某种特殊情况下,带符号的除法也会溢出。
// 带符号的n位类型可以表示-2^(n-1),但不足以表示2^(n-1)
assert_eq!((-128_i8).checked_div(-1), None);
1.4.2 回绕运算

回绕运算会返回与"数学意义上正确的结果"对"值类型范围"取模的值相等的值。

rust 复制代码
// 第一个结果可以表示为u16,第二个则不能,所以会得到250000 对216的模
assert_eq!(100_u16.wrapping_mul(200), 20000);
assert_eq!(500_u16.wrapping_mul(500), 53392);

// 对有符号类型的运算可能会回绕为负值
assert_eq!(500_i16.wrapping_mul(500), -12144);

// 在移位运算中,移位距离会在值的大小范围内回绕,
// 所以在16位类型中移动17位就相当于移动了1位
assert_eq!(5_i16.wrapping_shl(17), 10);
1.4.3 饱和运算

饱和运算会返回最接近"数学意义上正确结果"的可表达值。换句话说,结果"紧贴着"该类型可表达的最大值和最小值。

rust 复制代码
assert_eq!(32760_i16.saturating_add(10), 32767);
assert_eq!((-32760_i16).saturating_sub(10), -32768);

不存在饱和除法、饱和求余法或饱和位移法

1.整数相除一般不会溢出,即使溢出也没有"数学意义上的正确结果"

2.饱和是对溢出的一种补救方式,余数不可能溢出,因此饱和也没有意义

3.饱和是对溢出的一种补救方式,移位的溢出在不同情况下补救方式不同,因此无法统一支持

1.4.4 溢出运算

溢出运算会返回一个元组 (result, overflowed),其中 result 是函数的回绕版本所返回的内容,而 overflowed 是一个布尔值,指示是否发生过溢出。

rust 复制代码
assert_eq!(255_u8.overflowing_sub(2), (253, false));
assert_eq!(255_u8.overflowing_add(2), (1, true));

前缀 checked_、wrapping_、saturating_ 或 overflowing_ 后面可以跟着的运算名称如下表所示:

运算 名称后缀 例子
加法 add 100_i8.checked_add(27) == Some(127)
减法 sub 10_u8.checked_sub(11) == None
乘法 mul 128_u8.saturating_mul(3) == 255
除法 div 64_u16.wrapping_div(8) == 8
求余 rem (-32768_i16).wrapping_rem(-1) == 0
取负 neg (-128_i8).checked_neg() == None
绝对值 abs (-32768_i16).wrapping_abs() == -32768
求幂 pow 3_u8.checked_pow(4) == Some(81)
按位左移 shl 10_u32.wrapping_shl(34) == 40
按位右移 shr 40_u64.wrapping_shr(66) == 10

相关推荐
sealaugh322 小时前
aws(学习笔记第四十八课) appsync-graphql-dynamodb
笔记·学习·aws
水木兰亭2 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
鱼摆摆拜拜3 小时前
第 3 章:神经网络如何学习
人工智能·神经网络·学习
aha-凯心3 小时前
vben 之 axios 封装
前端·javascript·学习
freexyn4 小时前
Matlab自学笔记六十一:快速上手解方程
数据结构·笔记·matlab
很小心的小新5 小时前
12、jvm运行期优化
java·开发语言·jvm·笔记
ytttr8736 小时前
matlab通过Q学习算法解决房间路径规划问题
学习·算法·matlab
寻丶幽风7 小时前
论文阅读笔记——NoPoSplat
论文阅读·笔记·三维重建·3dgs·相机位姿·dustr
听风ツ9 小时前
固高运动控制
学习
西岭千秋雪_9 小时前
Redis缓存架构实战
java·redis·笔记·学习·缓存·架构