Rust 数组
数组(array)是一组长度固定、类型相同的值。关键词是“长度固定”:数组一旦创建,就不能再变长或变短。如果需要能改变大小的列表,那是 vector 的工作。
fn main() { let numbers: [i32; 5] = [1, 2, 3, 4, 5]; println!("{:?}", numbers);}类型 [i32; 5] 读作“由 5 个 i32 值组成的数组”。长度是类型的一部分:[i32; 5] 和 [i32; 3] 是两种不同的类型。
也可以不写类型,只写值,让 Rust 自己推断:
let numbers = [1, 2, 3, 4, 5];同一个值重复多次
Section titled “同一个值重复多次”想用同一个值把数组填满 N 次,可以用这种简写:
fn main() { let zeros = [0; 5]; // [0, 0, 0, 0, 0] println!("{:?}", zeros);}数组的索引从 0 开始,用方括号来访问:
fn main() { let fruits = ["苹果", "香蕉", "樱桃"];
println!("{}", fruits[0]); // 苹果 println!("{}", fruits[2]); // 樱桃 println!("元素个数:{}", fruits.len());}越界访问会被拦下来
Section titled “越界访问会被拦下来”如果访问一个不存在的索引,Rust 会直接停止程序,而不是悄悄读出一堆垃圾数据:
fn get_fruit(fruits: [&str; 3], index: usize) -> &str { fruits[index]}
fn main() { let fruits = ["苹果", "香蕉", "樱桃"]; println!("{}", get_fruit(fruits, 10)); // 运行时会 panic}thread 'main' (12345) panicked at src/main.rs:2:5:index out of bounds: the len is 3 but the index is 10这条 panic 信息的意思是:“索引越界:长度是 3,但索引是 10”。
fn main() { let numbers = [10, 20, 30];
for n in numbers { println!("{n}"); }}数组的数组(二维数组)
Section titled “数组的数组(二维数组)”数组里也可以放数组。这样就得到一个有行有列的网格,比如棋盘或者一张小表格。下面 grid 的类型是 [[i32; 3]; 2],读作“2 行,每行是一个由 3 个 i32 值组成的数组”。
fn main() { // 2 行 3 列 let grid = [ [1, 2, 3], [4, 5, 6], ];
println!("第 1 行第 2 列:{}", grid[1][2]);
let mut total = 0; for row in grid { println!("{:?}", row); for value in row { total += value; } } println!("总和:{total}");}输出:
第 1 行第 2 列:6[1, 2, 3][4, 5, 6]总和:21grid[1][2] 的意思是“先取第 1 行,再取这一行里的第 2 列”。行和列都从 0 开始数,所以这里其实是第二行的第三个值。要访问每一个值,就用一个循环遍历各行,再在里面套一个循环遍历这一行的值。
每一行的长度都必须相同,因为行的长度是类型的一部分。如果遍历时还需要知道每个位置的索引,可以用 .iter().enumerate() 同时拿到索引和值,for 循环那一课里有介绍。
数组和 vector 的区别
Section titled “数组和 vector 的区别”如果大小固定、事先就知道(比如一周七天),就用数组。如果需要添加或删除元素,就用 Vec,而实际写代码时大多数情况都是这样。在日常的 Rust 代码里,数组远没有 vector 常见。
1. 求和与平均值
Section titled “1. 求和与平均值”创建数组 [4, 8, 15, 16, 23, 42]。把所有值加起来,然后打印总和,以及保留两位小数的平均值。提示:用 for 循环,维护一个不断累加的 total,做除法之前用 as 把两个数都转成 f64。
查看答案
fn main() { let numbers = [4, 8, 15, 16, 23, 42];
let mut total = 0; for n in numbers { total += n; }
let average = total as f64 / numbers.len() as f64; println!("总和:{total}"); println!("平均值:{average:.2}");}输出:
总和:108平均值:18.00如果不写 as f64,total / numbers.len() 就是整数除法,而且 Rust 还会报错,说 total(i32)和 len()(usize)是不同的类型。
2. 最热的一天
Section titled “2. 最热的一天”这里有一周的气温:[18, 25, 12, 31, 22, 27, 19]。找出最高的那个并打印出来。提示:先写 let mut hottest = temps[0];,然后循环,每遇到更大的值就替换它。
查看答案
fn main() { let temps = [18, 25, 12, 31, 22, 27, 19];
let mut hottest = temps[0]; for t in temps { if t > hottest { hottest = t; } }
println!("最热的一天:{hottest}");}输出:
最热的一天:31从 temps[0] 开始而不是从 0 开始很重要:如果每天的气温都在零度以下,从 0 开始就会得到错误的答案。
- 数组的长度固定,而且长度是类型的一部分:
[i32; 5]。 - 用
array[index]访问元素,索引从 0 开始。 - 越界访问会在运行时 panic,而不会导致未定义行为。
- 数组里可以放数组:
[[i32; 3]; 2]是一个网格,用grid[行][列]来读取。 - 需要改变大小时,改用
Vec。
小测验
1. 关于 Rust 数组的长度,哪种说法是对的?
2. 在运行时访问越界的数组索引会发生什么?
3. let zeros = [0; 5]; 创建的是什么?
得分: 0 / 3
- 数组类型 —《Rust 程序设计语言》:官方教程对数组的介绍,包括为什么长度是类型的一部分。
- 数组和切片 — 通过例子学 Rust:简短的可运行示例,还能初步认识 slice。
- 使用 for 遍历集合 —《Rust 程序设计语言》:为什么用
for循环比用索引逐个访问数组更安全。 array— 标准库文档(英文):数组能做什么,比如map和as_slice,以及数组怎样借用 slice 的全部方法。