变量
- 使用 let 关键字。
- 默认不可变,加 mut(mutable)为可变。
- 不必显性声明数据类型。
- 可遮蔽 (shadow):使用相同的变量名并重复使用 let 关键字遮蔽变量。
let x = 5;
x = 6; // error
let x = x + 1; // shadow, this 'x' is 6
let mut x = "hello"; // shadow
常量
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
- 使用 const 关键字。
- 不可变,所以不能使用 mut。
- 必须显性声明数据类型。
- 常量只能设置为常量表达式,而不能是运行时计算的结果,如调用函数得到的值。
数据类型
- Rust 是静态类型(statically typed)语言,这意味着它必须在编译期知道所有变量的类型。
- 通常可以自动推导出类型,但某些情况需人为指定。
// default typed
let x = 5; // i32
// 人工确认u32,否则编译不通过。
let guess: u32 = "42".parse().expect("Not a number!");
标量类型
- 标量(scalar)类型表示单个值。Rust 有 4 个基本的标量类型:整型、浮点型、布尔、字符。
整型
- 默认整型是 i32。
- 有符号以 i(integer)开始,无符号以 u (unsigned)开始。有符号类型的范围是 -(2n - 1) ~ 2n - 1 - 1。
- isize 和 usize 取决于操作系统, isize 在64位操作系统中等于i64,32位中等于 i32,主要应用场景是用作某些集合的索引。
- 可以使用字面量声明。例:十进制 1_000 = 1000,十六进制 0x41 = 字节 “A” = 65 // TODO
字节 | 有符号 | 范围 | 无符号 | 范围 |
---|---|---|---|---|
2 | i8 | -128~127 | u8 | 0~255 |
4 | i16 | //TODO | u16 | |
6 | i32 | u32 | ||
8 | i64 | u64 | ||
10 | i128 | u128 | ||
4/8 | isize | usize |
let x = 1; // i32
let x = "A"; // i32 //TODO
let x: i64 = 1_000; // i64
整数溢出
当存储的数据大于数据类型的最大限度后会出现整型溢出(integer overflow),有两种情况:
- 调试(debug)模式编译时会自动检查,若存在该问题则编译时 panic。
- 发布(release)模式构建时不检测。如果发生会二进制补码包裹(two’s complement wrapping)。
大于该类型最大值的数值会被“包裹”成该类型能够支持的对应数字的最小值。例 u8,256 变成 0,257 变成 1,依此类推。
:::warning ⚠️依赖整型溢出包裹的行为不是一种正确的做法。因为该变量的值可能不是期望的值。
:::
要显式处理溢出的可能性,可以使用标准库针对原始数字类型提供的以下一系列方法:
- 使用 wrapping_* 方法在所有模式下进行包裹,例如 wrapping_add
- 如果使用 checked_* 方法时发生溢出,则返回 None 值
- 使用 overflowing_* 方法返回该值和一个指示是否存在溢出的布尔值
- 使用 saturating_* 方法使值达到最小值或最大值
浮点型
- 默认浮点型是 f64。因为现代 CPU 的速度与 f32 的几乎相同,但精度更高。
- 所有浮点型都是有符号的。
- 浮点数按照 IEEE-754 标准表示,所以运算时需确保精度的准确。
字节 | 名称 | 小数点位数 |
---|---|---|
4 | f32(单精度浮点) | 6 |
8 | f64(双精度浮点) | 12 |
let x = 2.0; // f64
let y: f32 = 3.0; // f32
布尔
- true 和 false,大小为 1 个字节。
let t = true;
let f: bool = false;
字符
- 大小为 4 个字节,表示的是一个 Unicode 标量值。例:标音字母、中/日/韩文、emoji。
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
复合类型
元组(tuple)
- 元组是将多种类型的多个值组合到一个复合类型中的一种基本方式。
- 长度固定,声明后无法增长或缩小。
let tup: (i32, f64, u8) = (500, 6.4, 1);
let tup = (500, 6.4, 1);
// use mode: destructuring
let (x, y, z) = tup; // 解构
println!("The value of y is: {}", y);
// use mode: index
println!("The value of y is: {}", tup.1);
元组也可以完成多返回值的功能。
fn main() {
let (res1, res2) = f1(1);
}
fn calculate_length(i: i32) -> (i32, i32) {
(1, 2)
}
数组(array)
- 将多个值组合在一起且都是同一数据类型的结构为数组。
- 长度固定,声明后无法增长或缩小。这样可以分配到内存的栈(stack)而不是堆(heap),从而提高性能。
⚠️ 如果想长度动态,可使用 vector 动态数组。
- 它类似标准库中提供的集合类型,其大小允许增长或缩小。
- 如果不确定是使用 array 还是 vector,那你就选择 vector。