Rust vector(Vec)
vector(Vec)和数组很像,但它可以在运行时变长或变短。在日常的 Rust 代码里,需要一个列表时,你用到 Vec 的次数会远远多于固定长度的数组。
创建 vector
Section titled “创建 vector”fn main() { let numbers: Vec<i32> = vec![1, 2, 3]; println!("{:?}", numbers);}vec![] 是一个宏(注意那个 !),它用一串值构建出一个 Vec,写法和数组字面量差不多。
也可以先创建一个空的,再一点点往里加:
let mut numbers: Vec<i32> = Vec::new();用 .push() 把元素加到末尾。因为要修改 vector,所以它必须是 mut 的:
fn main() { let mut numbers = Vec::new();
numbers.push(1); numbers.push(2); numbers.push(3);
println!("{:?}", numbers);}输出:
[1, 2, 3]和数组一样,用方括号:
fn main() { let fruits = vec!["苹果", "香蕉", "樱桃"];
println!("{}", fruits[0]); println!("元素个数:{}", fruits.len());}想要更安全、索引不对时也不会 panic 的查找方式,就用 .get(),它返回的是一个 Option(详见 Option 那一课):
fn main() { let fruits = vec!["苹果", "香蕉", "樱桃"];
match fruits.get(10) { Some(fruit) => println!("找到了:{fruit}"), None => println!("这个索引上没有水果"), }}fn main() { let mut numbers = vec![1, 2, 3, 4, 5];
numbers.pop(); // 删除最后一个元素 -> [1, 2, 3, 4] numbers.remove(0); // 按索引删除 -> [2, 3, 4]
println!("{:?}", numbers);}遍历 vector
Section titled “遍历 vector”fn main() { let numbers = vec![10, 20, 30];
for n in &numbers { println!("{n}"); }}注意 numbers 前面的 &:用 for n in &numbers 遍历时,每个元素都是被借用的,而不是拿走整个 vector 的所有权。如果去掉 &,vector 就会被移动到循环里,之后就不能再用 numbers 了。几乎所有时候,你想要的都是借用。
简单说说泛型
Section titled “简单说说泛型”你可能注意到了,类型写的是 Vec<i32>。<i32> 这部分表示“一个装着 i32 值的 vector”。这种尖括号写法叫作泛型(generics),泛型那一课会正式讲到它。现在只要把 Vec<T> 读作“一个存放 T 类型值的 vector”就行。
1. 收集偶数
Section titled “1. 收集偶数”从一个空的 vector 开始。遍历 1 到 10,只把偶数 push 进去。然后打印这个 vector,以及它有多少个元素。提示:当 n % 2 == 0 时,数字 n 就是偶数。
查看答案
fn main() { let mut evens = Vec::new();
for n in 1..=10 { if n % 2 == 0 { evens.push(n); } }
println!("{:?}", evens); println!("找到了 {} 个偶数", evens.len());}输出:
[2, 4, 6, 8, 10]找到了 5 个偶数注意我们一直没写类型。Rust 看到了 push(n) 的调用,就推断出 evens 是一个 Vec<i32>。
2. 一摞盘子
Section titled “2. 一摞盘子”往 vector 里放三个盘子:先 "蓝色",再 "绿色",最后 "红色"。用 .pop() 从最上面拿走两个盘子,每拿一个就打印一次。最后打印还剩下什么。提示:.pop() 返回的是 Option,所以要用 {:?} 打印。
查看答案
fn main() { let mut plates = Vec::new(); plates.push("蓝色"); plates.push("绿色"); plates.push("红色");
println!("拿走了 {:?}", plates.pop()); println!("拿走了 {:?}", plates.pop()); println!("还剩:{:?}", plates);}输出:
拿走了 Some("红色")拿走了 Some("绿色")还剩:["蓝色"]pop() 总是拿走你最后放进去的那个元素,就像从一摞盘子的最上面拿一个。它返回的是 Some(...) 而不是值本身,因为 vector 有可能是空的。那种情况下你会得到 None,而不是程序崩溃。
Vec<T>是可以增长的列表,用vec![...]或Vec::new()创建。.push()加到末尾,.pop()删除最后一个元素,.remove(i)按索引删除。- 索引不对时,
vec[i]会 panic,而.get(i)返回一个Option,不会 panic。 - 用
for item in &vec遍历,借用每个元素,而不是消耗掉整个 vector。
小测验
1. 用一个不存在的索引访问 Vec(比如 numbers[10])会发生什么?
2. 哪个方法可以按索引查找元素,又不用担心 panic?
3. for n in &numbers 里的 & 有什么作用?
得分: 0 / 3
- 使用 Vector 储存列表 —《Rust 程序设计语言》:vector 的创建、读取和更新,以及为什么持有引用时不能 push。
- 动态数组 vector — 通过例子学 Rust:一个可运行的例子,演示
Vec最常用的操作。 Vec— 标准库文档(英文):全部方法的列表,比如insert、retain、extend和contains。vec!宏 — 标准库文档(英文):vec!的所有写法,包括表示重复值的vec![0; 10]。