数据类型
整型 iN/uN
Rust 整型有:i8
/u8
, i16
/u16
, i32
/u32
, i64
/u64
, i128
/u128
, isize
/usize
其中 iN
/uN
表示该类型长度为 N bits (即 N/8 Bytes),有符号类型范围为 [-2(N-1), 2(N-1)-1],无符号类型的范围为 [0, 2^N-1]。
isize
/usize
依赖于系统架构(64位还是 32 位)。
在 64 位系统中,isize
是 64 bits 即 8 Bytes,但是它并不等同于 i64
。
Rust 默认使用 i32
表示整型(let x = 1;
),如果需要使用其他类型,需要显示指定类型(let x: i64 = 1;
or let x = 1i64;
)。
使用类型后缀形式(1i64
)时,实际数值不能超过类型允许的范围,例如 128i8
是不合法的,127i8
是合法的。
允许使用下划线作为数字分隔符方便读书,例如 1_2_3_4
与 1234
等价,再例如 12_345_678
。
整型字面值 Literals
除了十进制字面值(例如 123
, -123
)外,还可以使用其它进制的字面量:
- 十六进制以 0x 开头,例如
0xff
与255
等价 - 八进制以 0o 开头,例如
0o377
与255
等价 - 二进制以 0b 开头,例如
0b_1111_1111
与255
等价
此外 u8
还可以表示 单字节字符 字面量:let x: u8 = b'A';
(这里只能用单引号)
整型溢出 Integer Overflow
溢出指的是变量实际接收的值超出了变量类型的范围,如将 256
赋给 i8
类型的变量。
溢出有两种处理方式:
- 退出程序:这是 debug 模式下的默认行为
- 进行一定的自动纠正,避免程序退出。具体的纠正方法有:
- 在变量类型取值范围内从小到大循环取值,即 wrapping
- 在达到最大或者最小值边界时停止取值,即 saturating
自动纠正机制在大部分情境下可能是没有意义的,因此我们需要在程序中手动检测溢出,必要时指定如何纠正溢出。
release 模式下溢出时会自动执行 wrapping 操作。
Rust 为基本操作提供了对应的变种方法用于手动处理溢出问题:
.wrapping_*
方法进行 wrapping 操作.checked_*
方法出现溢出时会返回None
值.overflow_*
方法返回一个 wrapping 值和表示是否发生溢出的布尔值saturating_*
方法在发生溢出时取最大或者最小值
fn main() {
// wrapping_*
println!("{}", 127i8.wrapping_add(2i8));
println!("{}", 255u8.wrapping_add(2u8));
// checked_* 溢出时返回 None
match 255u8.checked_add(2u8) {
None => println!("None"),
Some(v) => println!("{v}"),
};
// overflow_* 返回TCW结果值和表示是否溢出的布尔值
let (v, st) = 255u8.overflowing_add(2u8);
println!("v={v}, is_overflow={st}");
// saturating_* 在最大最小值处饱和处理
println!("{}", 255u8.saturating_add(2u8));
}
-127
1
None
v=1, is_overflow=true
255
浮点数 fN
类型:f32
, f64
(默认),有符号。
数值运算
整数除法会向 0 舍入到最近的整数:
99 / 100
returns0
-99 / 100
returns0
取余运算:43 % 5
returns 3
布尔类型 bool
let st: bool = true;
字符类型 char
char
类型大小为 4 字节(32 bits),用来表示 Unicode 标量值。
前面提到的字面量
b'A'
本质上是整型(u8
),它指的应该是 ASCII 表中定义的单字节字符。
let heart_eyed_cat = '😻';
Rust 区分单引号和双引号:单引号用于 Unicode 字符字面量,双引号用于字符串字面量。
单字节字面量中也是用的单引号:
b'A'
原生复合类型:元组
let t1 = (500, 64.0, 1);
let t2: (i32, f64, u8) = (500, 64.0, 1);
let (x, y, z) = t2;
- 元组的每个元素的类型可以不同,元组变量类型可以通过类型注解显式指定,也可以从元组值中自动推断
- 模式 pattern:上面用来解构元组
t2
的(x, y, z)
就是一个模式 - 模式匹配 pattern matching:使用模式来解构元组的这个过程就是模式匹配
- 解构 destructure:使用模式匹配从元组中提取元素到模式中的变量中的操作就是解构
- 元组解构时不需要指定模式中各变量的类型,因为元组本身每个元素的类型就是已知的
- 除了模式解构外,还可以通过索引来访问元组元素,例如访问第一个元素
t2.0
- 单元元组 unit tuple:值和类型都为
()
,表达式或者函数不返回其他值时默认返回这个
原生复合类型:数组
- 数组的每个元素的类型必须一致,可以手动指定,或者自动从值列表推断
- 数组的长度在编译时是已知的(这点与 C++ 一致),变长数组请使用 vector 类型
- 数组是位于栈中的单个内存块
// 从值列表推断数组类型
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
// 指定数组类型
let a: [i32; 5] = [1, 2, 3, 4, 5];
// 创建值相同的数组
let a = [3; 5]; // 等价于 let a: [i32; 5] = [3, 3, 3, 3, 3];
- 数组元素通过索引访问(
a[0]
,元组是t.0
) - 程序运行时访问超出数组索引范围的元素会引发运行时错误
评论区