Rust 是一中静态类型语言,所以在编译时需要知道变量的类型。这样我们再编写代码的时候就需要定义变量的数据类型,这样才能保证编译通过。在 Rust 中有两种数据类型:标量
和 复合
。例如如下代码:
let guess: u32 = "42".parse().expect("Not a number!");
println!("guess: {}", guess);
假如上面的代码去掉u32
变量声明的话,系统在编译的时候则会发生错误。错误代码如下:
--> src\main.rs:2:7
|
2 | let guess = "42".parse().expect("Not a number!");
| ^^^^^
|
help: consider giving `guess` an explicit type
|
2 | let guess: /* Type */ = "42".parse().expect("Not a number!");
| ++++++++++++
标量类型
标量类型就是单个值。而标量类型主要有:整数
、浮点数
、布尔值
和字符
。
整数
Rust 中的整数类型
长度 | 有符号 | 无符号 |
---|---|---|
8 位 | i8 | u8 |
16 位 | i16 | u16 |
32 位 | i32 | u32 |
64 位 | i64 | u64 |
128 位 | i128 | u128 |
arch | isize | usize |
有符号和无符号只是确保数字是否可以存在负数。每个带符号的变量可以储存从-2 的 n-1 次方到 2 的 n-1 次方减 1 的数字。而无符号的则是从 0 到 2 的 n-1 次方减 1 的数字。n 表示的位数。
此外,isize
和usize
类型取决于运行程序的计算机的体系结构。如果您使用的是 64 位体系结构,则为 64 位;如果您使用的是 32 位,则为 32 位架构。
Rust 中数字进制的表示
进制 | 例子 |
---|---|
十进制 | 98_222 |
十六进制 | 0xff |
八进制 | 0o77 |
二进制 | 0b1111_0000 |
字节(尽在 u8 有效) | b’A’ |
Rust 的默认值情况
- 整数类型默认为 i32
- isize 您将使用或 usize 索引某种集合的主要情况
整数溢出
在 Rust 中对数据溢出的处理情况主要有两种情况需要注意。
-
调试模式下
在这种情况下 Rust 会检查整数溢出,当发生溢出时,程序在运行时则会出现报错或者程序退出。
-
发布模式下
在发布模式下,我们使用
--release
编译发布程序后,程序是不会帮我们检测数据溢出的,假如程序中发出溢出时,Rust 会执行二进制补码操作。即大于该类型可以容纳的最大值的值“环绕”到该类型可以容纳的最小值。例如变量 a 声明类型为 u8,值 256 会变成 0,值 257 会变成 1,依次类推,这样程序不会产生退出情况,但是数据的准确性不高。
要显式处理溢出的可能性,您可以使用标准库为原始数字类型提供的这些方法族:
- 使用方法包装所有模式 wrapping_*,例如 wrapping_add
- None 如果方法溢出,则返回该值 checked_*
- 返回值和一个布尔值,指示方法是否溢出 overflowing_*
- 使用方法在值的最小值或最大值处饱和 saturating_*
浮点类型
Rust 也有两种基本类型的浮点数,它们是带小数点的数字。Rust 的浮点类型是 f32 和 f64,它们的大小分别为 32 位和 64 位。
默认类型是 f64 因为在现代 CPU 上,它的速度与 大致相同,f32 但精度更高。所有浮点类型都是有符号的。
数值计算
Rust 支持所有数字类型的基本数学运算:加法、减法、乘法、除法和余数。整数除法向零截断到最接近的整数。
let sum = 5 + 10;
let difference = 95.5 - 4.3;
let product = 4 * 30;
let quotient = 56.7 / 32.2;
let truncated = -5 / 3;
let remainder = 43 % 5;
println!("sum: {}", sum); // 15
println!("difference: {}", difference); // 91.2
println!("product: {}", product); // 120
println!("quotient: {}", quotient); // 1.7608695652173911
println!("truncated: {}", truncated); // -1
println!("remainder: {}", remainder); // 3
布尔类型
Rust 中的布尔类型有两个可能的值:true 和 false。
字符类型
Rust 的 char 类型是该语言最原始的字母类型。具体实例如下:
let c = 'z';
let z: char = 'ℤ'; // with explicit type annotation
let heart_eyed_cat = '😻';
println!("c is {}", c);
println!("z is {}", z);
println!("heart_eyed_cat is {}", heart_eyed_cat);
请注意,我们使用 char 单引号指定文字,而不是使用双引号的字符串文字。Rust 的 char 类型大小为四个字节,表示一个 Unicode 标量值,这意味着它可以表示的不仅仅是 ASCII。重音字母、中文、日文和韩文字符、表情符号,char 和零宽度空格在 Rust 中都是有效值。Unicode 标量值的范围从 U+0000 到 U+D7FF 到 U+E000 到 U+10FFFF 包括。但是,char 在 Unicode 中并不是一个真正的概念。
复合类型
在 Rust 有两种原始复合类型:元组
和 数组
。
元组类型
元组是可以存放多种数据类型的一个复合体,但是它一旦声明长度就不能增加和缩小。需要获取元组中的对应下标值可以使用.
来使用。例如:
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("tup in 1 = {}", tup.0);
变量 tup 绑定到整个元组,因为元组被视为单个复合元素。要从元组中获取单个值,我们可以使用模式匹配来解构元组值,如下所示:
let tup = (500, 6.4, 1);
let(x, y, z) = tup;
println!("The value of y is: {y}");
数组类型
与元组不同,数组的每个元素都必须具有相同的类型。与某些其他语言中的数组不同,Rust 中的数组具有固定长度。数组的访问跟其他语言是保持一致的。例如:
let a = [1, 2, 3, 4, 5];
println!("a[0] = {}", a[0]);
您可以使用方括号、每个元素的类型、分号和数组中元素的数量来编写数组的类型,如下所示:
let a: [i32; 5] = [1, 2, 3, 4, 5];
假如需要复制重复的值,可以使用如下形式进行定义:
let a = [3; 5];
当您尝试使用索引访问元素时,Rust 将检查您指定的索引是否小于数组长度。如果索引大于或等于长度,Rust 会停止系统运行并把错误报错。这种检查必须在运行时进行,尤其是在这种情况下,因为编译器不可能知道用户稍后运行代码时将输入什么值。
这是 Rust 的内存安全原则在实践中的一个例子。在许多低级语言中,并没有进行这种检查,当你提供一个不正确的索引时,就可以访问无效的内存。Rust 通过立即退出而不是允许内存访问和继续来保护您免受这种错误。