Rust 是 静态类型statically typed)语言,也就是说在编译时就必须知道所有变量的类型。根据值及其使用方式,编译器通常可以推断出我们想要用的类型。当多种类型均有可能时,必须增加类型注解。
  1. let guess = "42".parse().expect("Not a number!");
  2. let guess: u32 = "42".parse().expect("Not a number!");

标量类型

标量scalar)类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。

整型

长度 有符号 无符号
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize
isizeusize 类型依赖运行程序的计算机架构:64 位架构上它们是 64 位的, 32 位架构上它们是 32 位的。

浮点数

Rust 也有两个原生的 浮点数floating-point numbers)类型,它们是带小数点的数字。Rust 的浮点数类型是 f32f64,分别占 32 位和 64 位。默认类型是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。
  1. fn main() {
  2. let x = 2.0; // f64
  3. let y: f32 = 3.0; // f32
  4. }

数值运算

  1. fn main() {
  2. // 加法
  3. let sum = 5 + 10;
  4. // 减法
  5. let difference = 95.5 - 4.3;
  6. // 乘法
  7. let product = 4 * 30;
  8. // 除法
  9. let quotient = 56.7 / 32.2;
  10. // 取余
  11. let remainder = 43 % 5;
  12. }

布尔型

  1. fn main() {
  2. let t = true;
  3. let f: bool = false; // 显式指定类型注解
  4. }

字符类型

Rust 的 char 类型是语言中最原生的字母类型, char 由单引号指定,不同于字符串使用双引号。
  1. fn main() {
  2. let c = 'z';
  3. let z = 'ℤ';
  4. let heart_eyed_cat = '😻';
  5. }
Rust 的 char 类型的大小为四个字节(four bytes),并代表了一个 Unicode 标量值(Unicode Scalar Value),这意味着它可以比 ASCII 表示更多内容。

复合类型

复合类型Compound types)可以将多个值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和数组(array)。

元组类型

元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增大或缩小。
  1. fn main() {
  2. let tup: (i32, f64, u8) = (500, 6.4, 1);
  3. }
  4. // 程序首先创建了一个元组并绑定到 tup 变量上。
  5. // 接着使用了 let 和一个模式将 tup 分成了三个不同的变量,x、y 和 z。
  6. // 这叫做 解构(destructuring),因为它将一个元组拆成了三个部分。
  7. fn main() {
  8. let tup = (500, 6.4, 1);
  9. let (x, y, z) = tup;
  10. println!("The value of y is: {}", y);
  11. }
  12. fn main() {
  13. let x: (i32, f64, u8) = (500, 6.4, 1);
  14. let five_hundred = x.0;
  15. let six_point_four = x.1;
  16. let one = x.2;
  17. }

数组类型

与元组不同,数组中的每个元素的类型必须相同。Rust 中的数组与一些其他语言中的数组不同,因为 Rust 中的数组是固定长度的:一旦声明,它们的长度不能增长或缩小。 当你想要在栈(stack)而不是在堆(heap)上为数据分配空间,或者是想要确保总是有固定数量的元素时,数组非常有用。但是数组并不如 vector 类型灵活。vector 类型是标准库提供的一个 允许 增长和缩小长度的类似数组的集合类型。当不确定是应该使用数组还是 vector 的时候,你可能应该使用 vector。
  1. let a = [1, 2, 3, 4, 5];
  2. let a: [i32; 5] = [1, 2, 3, 4, 5];
  3. let a = [3; 5]; // 变量名为 a 的数组将包含 5 个元素,这些元素的值最初都将被设置为 3。
  1. fn main() {
  2. let a = [1, 2, 3, 4, 5];
  3. let first = a[0];
  4. let second = a[1];
  5. }
  1. fn main() {
  2. let a = [1, 2, 3, 4, 5];
  3. let index = 10;
  4. let element = a[index];
  5. println!("The value of element is: {}", element);
  6. }

String

字符串字面值,即被硬编码进程序里的字符串值。字符串字面值是很方便的,不过它们并不适合使用文本的每一种场景。原因之一就是它们是不可变的。另一个原因是并非所有字符串的值都能在编写代码时就知道。 这个类型被分配到堆上,所以能够存储在编译时未知大小的文本。
  1. { // s 在这里无效, 它尚未声明
  2. let s = "hello"; // 从此处起,s 是有效的
  3. // 使用 s
  4. } // 此作用域已结束,s 不再有效
  1. let mut s = String::from("hello");
  2. s.push_str(", world!"); // push_str() 在字符串后追加字面值
  3. println!("{}", s); // 将打印 `hello, world!`
为什么 String 可变而字面值却不行呢? 栈和堆都是代码在运行时可供使用的内存,但是它们的结构不同。栈以放入值的顺序存储值并以相反顺序取出值。