rust基本数据类型——复合类型
复合类型(Compound types)可以将多个值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和数组(array)。
元组类型
元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增大或缩小。
我们使用包含在圆括号中的逗号分隔的值列表来创建一个元组。元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。例如:
代码语言:javascript复制fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
变量 tup 被绑定了一个元组值 (500, 6.4, 1),该元组的类型是 (i32, f64, u8),也就是在rust中元组是由圆括号将多个类型组合在一起。rust的元组和python的元组非常类似,但是rust的元组必须由()包括起来,而python中并不需要。并且rust的元组也拥有元组解构的语法。下面是一个元组结构的例子。
代码语言:javascript复制fn main() {
// 元组变量tup
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 在rust中可以使用模式匹配(pattern matching)来解构元组。
let (x, y, z) = tup;
println!("{x}");
println!("{y}");
println!("{z}");
}
在rust中也可以直接使用. 下标
的方式来访问元组中的元素。例如:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("{}", tup.0);
println!("{}", tup.1);
println!("{}", tup.2);
}
注意,元组的下标是从0开始的。
单元类型
在rust中,我们称空元组为“单元类型”,这种类型在声明的时候类型为(),并且它只有唯一的值,也是()。单元类型占据的内存大小为0. 如果一个表达式不返回任何其他值,那么会隐式返回单元类型。例如:
代码语言:javascript复制fn main() {
let _t: () = ();
}
这里声明了_t的类型是(),并赋予它值()。
单元类型是非常有必要的,因为在rust里没有返回值的函数是“发散函数”,它们有单独的定义。而像main函数这样的,是有返回值的,main会隐式返回().
再比如,你可以用 () 作为 map 的值,表示我们不关注具体的值,只关注 key。 这种用法和 Go 语言的 struct{} 类似,可以作为一个值用来占位,但是完全不占用任何内存。
数组
大多数编程语言中都有数组,在rust中数组中的每个元素的类型必须相同,并且数组的长度是固定的。例如:
代码语言:javascript复制// 数组类型
let a = [1, 2, 3, 4, 5];
for i in a{
println!("{i}");
}
当需要进行声明类型的时候,可以像下面这样做。
代码语言:javascript复制let a: [i32; 5] = [1, 2, 3, 4, 5]; // [i32; 5]表示数组的大小是5,元素的类型是i32.
此外,你还可以通过在方括号中指定初始值加分号再加元素个数的方式来创建一个每个元素都为相同值的数组:
代码语言:javascript复制let a: [3; 5]
变量名为 a 的数组将包含 5 个元素,这些元素的值最初都将被设置为 3。这种写法与 let a = [3, 3, 3, 3, 3]; 效果相同,但更简洁。
访问数组元素,是使用数组名[下标]
的方式,例如:
let a:[i32; 5] = [3; 5]; // 数组中5个元素都是i32类型的3
println!("{}", a[0]);
数组越界访问
程序在索引操作中使用一个无效的值时导致 运行时 错误。例如:
代码语言:javascript复制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}");
}
此代码编译成功。如果您使用 cargo run 运行此代码并输入 0、1、2、3 或 4,程序将在数组中的索引处打印出相应的值。如果你输入一个超过数组末端的数字,如 10,你会看到类型下面这样的输出:
代码语言:javascript复制Please enter an array index.
10
thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:48:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
程序在索引操作中使用一个无效的值时导致 运行时 错误。程序带着错误信息退出,并且没有执行最后的 println! 语句。当尝试用索引访问一个元素时,Rust 会检查指定的索引是否小于数组的长度。如果索引超出了数组长度,Rust 会 panic,这是 Rust 术语,它用于程序因为错误而退出的情况。这种检查必须在运行时进行,特别是在这种情况下,因为编译器不可能知道用户在以后运行代码时将输入什么值。
除非是下面这种,在编译时就可以被检测到的越界行为,能够在编译期直接指出错误。
代码语言:javascript复制let a: [i32, 5] = [1,2,3,4,5];
println!("{}", a[10]); // 编译期即可发现该错误。