基本类型
Rust
每个值都有其确切的数据类型,分为两类:基本类型和复合类型。
基本类型往往是一个最小化原子类型,无法解构为其它类型(一般意义上来说),由以下组成:
- 数值类型:有符号整数(
i8
,i16
,i32
,i64
,isize
)、无符号整数(u8
,u16
,u32
,u64
,usize
)、浮点数(f32
,f64
)、以及有理数、复数。 - 字符串:字符串字面量和字符串切片
&str
。 - 布尔类型:
true
和false
。 - 字符类型:表示单个
Unicode
字符,存储为 4 个字节。 - 单元类型:即
()
,其唯一的值也是()
。
类型推导与标注
Rust 是一门 静态类型语言,编译器必须在编译期知道所有变量的类型。
但我们并不需要手动指定每个变量的类型。
Rust 编译器可以根据变量的值和上下文中的使用方式来自动推导变量的类型。
但是,在某些情况下,它也无法推导出变量类型,需要手动去给出一个类型标注。
数值类型
整数类型
有符号类型和无符号类型。8、16、32、64、128位,和视结构而定的 isize
与 usize
。如果计算机CPU是32位,则为32位。如果是64位,则它们是64位。
整数的表示方式有:
数字字面量 | 示例 |
---|---|
十进制 | 10_000 |
十六进制 | 0X986 |
八进制 | 0o127 |
二进制 | 0b1111_0000 |
字节(仅限于 u8 ) | b’A’ |
整数溢出
当出现整型溢出时,Rust在 debug 时,会发现问题,使程序在编译时 panic。
如果在使用 release 模式构建时,Rust不会panic,而是补码循环溢出。
显式处理可能溢出的方法,使用标准库 针对原始数字类型 提出的方法:
- 使用
wrapping_*
方法在所有模式下都按照补码循环溢出处理。 - 如果使用
checked_*
方法时发生溢出,则返回None
值。 - 使用
overflowing_*
方法返回该值和一个指示是否存在溢出的布尔值。 - 使用
saturating_*
方法使值达到最小值或最大值。
浮点类型
浮点类型数字是带有小数点的数字。
有两种类型 f32
和 f64
。
默认为 f64
。
fn main(){let x = 2.0; // f64let y: f32 = 3.0;
}
浮点数陷阱
使用浮点数不谨慎会造成错误的原因:
- 浮点数往往是需要的数字的近似表达。通常我们所需要的数字是十进制的,而计算机中数字是二进制的。
- 浮点数在某些特性上是反直觉的。
避免方法:
- 避免在浮点数上测试相等性
- 当结果在数学上可能存在未定义时,需要格外的小心。
Nan
对于数学上未定义的结果,例如对负数取平方根就没有结果,Rust的浮点类型使用 Nan (not a number) 来处理这些情况。
所有 跟 NaN交互的操作,都会返回一个 NaN,而且 NaN 不能用于比较。
可以使用 is_nan()
等方法,判断一个值是否为 NaN。
fn main() {let x = (-42.0_f32).sqrt();if x.is_nan() {println!("未定义的数学行为")}
}
数字运算
Rust 支持所有数字类型的基本数字运算:加、减、乘、除和取模运算。
位运算
Rust 的位运算与其他语言一样。
运算符 | 说明 |
---|---|
& 位与 | 相同位置均为1时则为1,否则为0 |
位或 | 相同位置只要有1时则为1,否则为0 |
^ 异或 | 相同位置不相同则为1,相同则为0 |
! 位非 | 把位中的0和1相互取反,即0置为1,1置为0 |
<< 左移 | 所有位向左移动指定位数,右位补0 |
>> 右移 | 所有位向右移动指定位数,带符号移动(正数补0,负数补1) |
fn main() {// 二进制为00000010let a:i32 = 2;// 二进制为00000011let b:i32 = 3;println!("(a & b) value is {}", a & b);println!("(a | b) value is {}", a | b);println!("(a ^ b) value is {}", a ^ b);println!("(!b) value is {} ", !b);println!("(a << b) value is {}", a << b);println!("(a >> b) value is {}", a >> b);let mut a = a;// 注意这些计算符除了!之外都可以加上=进行赋值 (因为!=要用来判断不等于)a <<= b;println!("(a << b) value is {}", a);
}
序列 (Range)
Rust 提供了方式生成连续的数值。
如 1..5
,生成 1 到 4 的连续数字,不包含 5 。
1..=5
,生成 1 到 5 的连续数字,包含 5 。
for i in 1..=5 {println!("{}",i);
}
序列只允许用于数字或字符类型,原因是:它们可以连续,同时编译器在编译期可以检查该序列是否为空,字符和数字值是 Rust 中仅有的可以用于判断是否为空的类型。
使用 As 完成类型转换
Rust 中可以使用 As 来完成一个类型到另一个类型的转换,其最常用于将原始类型转换为其他原始类型,但是它也可以完成诸如将指针转换为地址、地址转换为指针以及将指针转换为其他指针等功能。
有理数和复数
Rust 的标准库并未包含有理数和复数。
- 有理数和复数
- 任意大小的整数和任意精度的浮点数
- 固定精度的十进制小数,常用于货币相关的场景
需要使用 库 num
。
按照以下步骤来引入 num
库:
- 创建新工程
cargo new complex-num && cd complex-num
- 在
Cargo.toml
中的[dependencies]
下添加一行num = "0.4.0"
- 将
src/main.rs
文件中的main
函数替换为下面的代码 - 运行
cargo run
use num::complex::Complex;fn main() {let a = Complex { re: 2.1, im: -1.2 };let b = Complex::new(11.1, 22.2);let result = a + b;println!("{} + {}i", result.re, result.im)}
总结
- Rust 的数值类型非常多,需要熟悉这些类型所占用的字节数。
- 类型转换必须是显式的。
- Rust的数值上可以使用方法。如取整
13.14_f32.round()
。