02-Rust基本类型之数值类型
Rust基本类型
Rust 每个值都有确切的数据类型,大致可以分为两类(基本类型和复合类型)
🍎基本类型
数值类型:
有符号整数 (i8, i16, i32, i64, isize)
无符号整数 (u8, u16, u32, u64, usize)
浮点数 (f32, f64)、以及有理数、复数
字符串:字符串字面量和字符串切片 &str
布尔类型:true 和 false
字符类型:表示单个 Unicode 字符,存储为 4 个字节
单元类型:即 () ,其唯一的值也是 ()
🍎类型推导与标注
Rust也包含有类型推导,跟其他语言差不多。就是推导数据类型。
数值类型
👉认识无符号数和有符号数
无符号数和有符号数是计算机中表示整数的两种方式,主要区别在于是否允许表示负数
🍎 有符号数(Signed Integer)
有符号数(正数、零和负数的整数)。计算机使用一个额外的位(通常是最高位)来表示符号。常见的表示方式有补码表示法。
- 补码表示法:最高位(最左边的一位)用来表示符号。0表示正数,1表示负数。
- 例如,8位有符号数:
11111111
表示 -1,00000001
表示 +1。 - 通过补码方式,可以轻松进行加减运算。
- 例如,8位有符号数:
🍎无符号数(Unsigned Integer)
无符号数(正数和零),没有符号位,因此所有位都用来表示数值大小。因为没有符号位,所以它的值域比有符号数多一倍。
- 例如,8位无符号数的范围是从 0 到 255(即 0 到 28−1)
- 无符号数的表示只能是正整数和零,无法表示负数
🍎举例说明:
- 8位有符号数:表示的范围是 -128 到 +127。
- 8位无符号数:表示的范围是 0 到 255。
👉整数类型
rust之中的整数可以概括为(有无符号 + 类型大小(位数))
Rust 整型默认使用 let i = 1
,那 i
就是 i32
类型,该类型也往往是性能最好的。
表示方法:没有小数部分的数字 i32
类型表示有符号的 32 位整数
i
代表有符号(英文单词 _integer_
缩写)
u
代表无符号 (英文单词 unsigned 缩写)
🍎内置的整数类型
长度 | 有符号类型 | 无符号类型 |
---|---|---|
8 位 | i8 | u8 |
16 位 | i16 | u16 |
32 位 | i32 | u32 |
64 位 | i64 | u64 |
128 位 | i128 | u128 |
视架构而定 | isize | usize |
🍎整型溢出
假设有一个 u8 ,它可以存放从 0 到 255 的值。那么当你将其修改为范围之外的值,比如 256,则会发生整型溢出(也就是当一个值超出它的整数类型的最大范围时会发生)
- 判定规则
当在 debug 模式编译时,Rust 会检查整型溢出,存在问题则使程序在编译时 panic(崩溃,Rust 使用这个术语来表明程序因错误而退出)
发生溢出以后,值会变成这个整型的最小值,遵循的是补码循环溢出(two’s complement wrapping)的规则
我们可以写一段代码进行检验
fn main() {
// 定义一个 u8 类型的变量,并赋予其最大值 255
let max_u8: u8 = 255;
println!("最大无符号 8 位整数值: {}", max_u8);
// 将变量加 1,导致溢出
let overflow_u8 = max_u8.wrapping_add(1);
println!("溢出后的值: {}", overflow_u8);
}
// 输出
最大无符号 8 位整数值: 255
溢出后的值: 0
- 如何跳过校验呢
使用 --release
参数进行 release 模式构建时,Rust 不检测溢出。
👉浮点类型
Rust 中浮点类型 分为f32
和 f64
两种,默认为f64
,根据 IEEE-754
标准实现
特性 | f32 | f64 (默认为这个) |
---|---|---|
大小 | 32 位 | 64 位 |
精度 | 单精度浮点数,精度约为 7 位有效数字 | 双精度浮点数,精度约为 15 位有效数字 |
默认类型 | 否 | 是 |
范围 | 大约 ±1.5 × 10^−45 到 ±3.4 × 10^38 | 大约 ±5.0 × 10^−324 到 ±1.8 × 10^308 |
使用场景 | 当对内存占用要求较高时(例如嵌入式系统) | 当需要更高精度时,例如科学计算 |
性能 | 在某些 CPU 上速度较快,但精度较低 | 在现代 CPU 上与 f32 性能相似,但提供更高精度 |
表示方式 | 采用 IEEE 754 单精度浮点数标准 | 采用 IEEE 754 双精度浮点数标准 |
🍎浮点类型数字
两种基本类型: f32
和 f64
默认浮点类型是 f64
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
🍎浮点数陷阱
🍎NaN
Rust 的浮点数类型使用 NaN
(not a number) 来处理数学上未定义的结果
👉数字运算
Rust 支持所有数字类型的基本数学运算,加减乘除如下
fn main() {
// 加法
let sum = 5 + 10;
// 减法
let difference = 95.5 - 4.3;
// 乘法
let product = 4 * 30;
// 除法
let quotient = 56.7 / 32.2;
// 求余
let remainder = 43 % 5;
}
👉位运算
Rust 的位运算如下:
运算符 | 说明 | |
---|---|---|
& 位与 | 相同位置均为1时则为1,否则为0 | |
位或 | 相同位置只要有1时则为1,否则为0 | |
^ 异或 | 相同位置不相同则为1,相同则为0 | |
! 位非 | 把位中的0和1相互取反,即0置为1,1置为0 | |
<< 左移 | 所有位向左移动指定位数,右位补0 | |
>> 右移 | 所有位向右移动指定位数,带符号移动(正数补0,负数补1) |
👉序列(Range)
Rust 提供了序列(Range)
方式用来生成连续的数值
1..5,生成从 1 到 4 的连续数字,不包含 5
1..=5,生成从 1 到 5 的连续数字,包含 5
常用于循环中:
//数字
for i in 1..=5 {
println!("{}",i);
}
// 最终程序输出
1
2
3
4
5
//字符
for i in 'a'..='z' {
println!("{}",i);
}
需要注意的是:序列只允许用于数字或字符类型
因为它们可以连续起来。其实思考一下,弄个汉字,完全不知道一个汉字背后应该放个啥。
编译器在编译期同时检查该序列是否为空
👉As类型转换
As 来完成一个类型到另一个类型的转换,这里有点类似TS
fn main() {
let i_terger:i32 = 10;
let f_terger:f64=i_terger as f64;
println!("i_terger is: {}", i_terger);
println!("f_terger is: {}", f_terger);
}
// 输出
i_terger is: 10
f_terger is: 10
👉有理数和复数
Rust 中处理有理数(Rational Numbers)和复数(Complex Numbers)并没有内建的类型
我们可以使用 num
外部库来处理有理数和复数,它提供了 Rational
和 Complex
类型
这里后续进行补充完善