文章目录
Rust 数据类型

在 Rust 中,每个值都有特定的数据类型,数据类型告诉 Rust 该如何处理这些数据。我们将介绍两类数据类型:标量类型和复合类型。
请注意,Rust 是静态类型语言,这意味着编译时必须知道所有变量的类型。编译器通常可以根据值和用法推断类型。但在某些情况下(比如将 String 转换为数字类型时),需要添加类型注解,例如:
rust
let guess: u32 = "42".parse().expect("Not a number!");
如果没有 : u32
类型注解,Rust 会报如下错误,提示需要更多类型信息:
$ cargo build
Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations)
error[E0284]: type annotations needed
--> src/main.rs:2:9
|
2 | let guess = "42".parse().expect("Not a number!");
| ^^^^^ ----- type must be known at this point
|
= note: cannot satisfy `<_ as FromStr>::Err == _`
help: consider giving `guess` an explicit type
|
2 | let guess: /* Type */ = "42".parse().expect("Not a number!");
| ++++++++++++
更多信息可通过 rustc --explain E0284
查看。其他数据类型也有类似的类型注解。
标量类型
标量类型表示单一值。Rust 有四种主要的标量类型:整数、浮点数、布尔值和字符。你可能在其他语言中也见过这些类型。
整数类型
整数是不带小数部分的数字。我们在第 2 章用过 u32
类型,表示 32 位无符号整数(有符号类型以 i
开头)。下表展示了 Rust 内置的整数类型:
长度 | 有符号 | 无符号 |
---|---|---|
8 位 | i8 | u8 |
16 位 | i16 | u16 |
32 位 | i32 | u32 |
64 位 | i64 | u64 |
128 位 | i128 | u128 |
架构相关 | isize | usize |
有符号类型可表示负数,无符号类型只能表示正数。Rust 使用二进制补码存储有符号数。
每种有符号类型能存储的范围是 −(2ⁿ⁻¹) 到 2ⁿ⁻¹−1,无符号类型是 0 到 2ⁿ−1。例如,i8 范围是 −128 到 127,u8 范围是 0 到 255。
isize
和 usize
的大小取决于计算机架构(32 位或 64 位)。
整数字面量可以用多种形式表示:
字面量类型 | 示例 |
---|---|
十进制 | 98_222 |
十六进制 | 0xff |
八进制 | 0o77 |
二进制 | 0b1111_0000 |
字节(u8) | b'A' |
如果不确定用哪种类型,Rust 默认使用 i32
。isize
和 usize
主要用于集合索引。
整数溢出
例如,u8
的范围是 0 到 255。如果赋值超出范围(如 256),在 debug 模式下会 panic;release 模式下会发生环绕(256 变为 0,257 变为 1)。依赖溢出行为是错误的。
Rust 提供了多种方法处理溢出:
wrapping_*
方法:始终环绕checked_*
方法:溢出时返回 Noneoverflowing_*
方法:返回值和是否溢出的布尔值saturating_*
方法:溢出时取最大或最小值
浮点类型
Rust 有两种浮点类型:f32
和 f64
,分别为 32 位和 64 位,默认是 f64
。所有浮点类型都是有符号的,遵循 IEEE-754 标准。
示例:
rust
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
数值运算
Rust 支持加、减、乘、除、取余等基本运算。整数除法向零取整。
rust
fn main() {
let sum = 5 + 10;
let difference = 95.5 - 4.3;
let product = 4 * 30;
let quotient = 56.7 / 32.2;
let truncated = -5 / 3; // 结果为 -1
let remainder = 43 % 5;
}
布尔类型
Rust 的布尔类型为 bool
,只有 true
和 false
两个值,占 1 字节。
rust
fn main() {
let t = true;
let f: bool = false; // 显式类型注解
}
布尔值主要用于条件表达式(如 if)。
字符类型
Rust 的 char
类型用于表示单个字符,4 字节,支持 Unicode 标量值。
rust
fn main() {
let c = 'z';
let z: char = 'ℤ';
let heart_eyed_cat = '😻';
}
字符字面量用单引号。char
能表示多种字符,包括表情、汉字等。
复合类型
复合类型可以将多个值组合成一个类型。Rust 有两种原生复合类型:元组和数组。
元组类型
元组可以将不同类型的多个值组合在一起,长度固定。
rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
可以使用模式匹配解构元组:
rust
fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {y}");
}
也可以通过索引访问元组元素:
rust
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
空元组 ()
被称为单元类型,表示空值或空返回类型。
数组类型
数组用于存储相同类型、固定长度的多个值。
rust
fn main() {
let a = [1, 2, 3, 4, 5];
}
数组适合需要固定数量元素且数据分配在栈上的场景。更灵活的可变长度集合请使用 vector。
数组类型写法:
rust
let a: [i32; 5] = [1, 2, 3, 4, 5];
也可以用相同值初始化:
rust
let a = [3; 5]; // 等价于 [3, 3, 3, 3, 3]
访问数组元素
通过索引访问数组元素:
rust
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
非法访问数组元素
如果访问越界(如索引为 10),程序会 panic:
rust
use std::io;
fn main() {
let a = [1, 2, 3, 4, 5];
println!("Please enter an array index.");
let mut index = String::new();
io::stdin()
.read_line(&mut index)
.expect("Failed to read line");
let index: usize = index
.trim()
.parse()
.expect("Index entered was not a number");
let element = a[index];
println!("The value of the element at index {index} is: {element}");
}
如果输入超出范围,程序会报错并退出:
thread 'main' panicked at src/main.rs:19:19:
index out of bounds: the len is 5 but the index is 10
Rust 在运行时检查索引是否合法,防止非法内存访问。这体现了 Rust 的内存安全原则。
代码示例如下:
rust
fn main() {
// 整数
let a = 10; // i32
let b: i64 = 20; // i64
// 打印整数
println!("Integer a: {}, b: {}", a, b);
// 浮点数
let x = 2.0; // f64
let y: f32 = 3.0; // f32
// 打印浮点数
println!("Float x: {}, y: {}", x, y);
// 数值类型转换
let int_to_float = a as f64; // i32 转 f64
let float_to_int = y as i32; // f32 转 i32
// 打印转换结果
println!("Converted int to float: {}, Converted float to int: {}", int_to_float, float_to_int);
// 数值运算
let sum = 5 + 10;
let difference = 95.5 - 4.3;
let product = 4 * 30;
let quotient = 56.7 / 32.2;
let truncated = -5 / 3; // 结果为 -1
let remainder = 43 % 5;
// 打印数值运算结果
println!("Sum: {}, Difference: {}, Product: {}, Quotient: {}, Truncated: {}, Remainder: {}",
sum, difference, product, quotient, truncated, remainder);
// 布尔值
let is_active = true; // bool
let is_valid: bool = false; // bool
// 字符
let c = 'A'; // char
let d: char = 'Z'; // char
let z: char = 'ℤ';
let heart_eyed_cat = '😻';
// 打印字符
println!("Character c: {}, d: {}, z: {}, heart_eyed_cat: {}", c, d, z, heart_eyed_cat);
// 字符串
let s = "Hello, world!"; // &str
let t: String = String::from("Hello, Rust!"); // String
// 元组
let tuple = (1, 2.5, 'c'); // (i32, f64, char)
let (x1, y1, z1) = tuple; // 解构元组
// 数组
let arr = [1, 2, 3, 4, 5]; // [i32; 5]
let arr2: [f64; 3] = [1.0, 2.0, 3.0]; // [f64; 3]
// 切片
let slice = &arr[1..4]; // &[i32]
let slice2: &[f64] = &arr2[0..2]; // &[f64]
// 枚举
enum Direction {
Up,
Down,
Left,
Right,
}
let dir = Direction::Up; // 使用枚举
// 结构体
struct Point {
x: f64,
y: f64,
}
let p = Point { x: 1.0, y: 2.0 }; // 创建结构体实例
// 使用结构体
println!("Point coordinates: ({}, {})", p.x, p.y);
// 使用枚举
match dir {
Direction::Up => println!("Moving up"),
Direction::Down => println!("Moving down"),
Direction::Left => println!("Moving left"),
Direction::Right => println!("Moving right"),
}
// 打印基本数据类型
println!("Integer a: {}, b: {}", a, b);
println!("Float x: {}, y: {}", x, y);
println!("Boolean is_active: {}, is_valid: {}", is_active, is_valid);
println!("Character c: {}, d: {}", c, d);
println!("String s: {}, t: {}", s, t);
println!("Tuple values: ({}, {}, {})", x1, y1, z1);
println!("Array values: {:?}", arr);
println!("Array2 values: {:?}", arr2);
println!("Slice values: {:?}", slice);
println!("Slice2 values: {:?}", slice2);
// 结束程序
println!("Program finished successfully.");
}
运行结果如下:
Integer a: 10, b: 20
Float x: 2, y: 3
Converted int to float: 10, Converted float to int: 3
Sum: 15, Difference: 91.2, Product: 120, Quotient: 1.7608695652173911, Truncated: -1, Remainder: 3
Character c: A, d: Z, z: ℤ, heart_eyed_cat: 😻
Point coordinates: (1, 2)
Moving up
Integer a: 10, b: 20
Float x: 2, y: 3
Boolean is_active: true, is_valid: false
Character c: A, d: Z
String s: Hello, world!, t: Hello, Rust!
Tuple values: (1, 2.5, c)
Array values: [1, 2, 3, 4, 5]
Array2 values: [1.0, 2.0, 3.0]
Slice values: [2, 3, 4]
Slice2 values: [1.0, 2.0]
Program finished successfully.