1. 创建新的向量
rust 提供了两种常用方式来创建向量:
使用 vec::new
当你需要创建一个空的向量时,可以调用 vec::new。
注意,由于向量中还没有元素,编译器无法自动推断向量中元素的类型,这时通常需要添加类型注解。
例如:
fn main() {
// 创建一个空的 vec<i32>
let mut v: vec<i32> = vec::new();
// 向向量中添加元素
v.push(5);
v.push(6);
v.push(7);
v.push(8);
println!("vector: {:?}", v);
}使用 vec! 宏
如果你希望一开始就初始化向量并指定初始值,可以使用 vec! 宏。
rust 会根据给定的初始值自动推导向量元素的类型:
fn main() {
// 创建一个包含初始值 1, 2, 3 的向量,类型会被推断为 vec<i32>
let v = vec![1, 2, 3];
println!("vector: {:?}", v);
}2. 更新向量
向量是动态大小的数据结构,可以通过调用 push 方法将新的元素添加到向量中。
需要注意的是,如果想要修改向量的内容,变量必须声明为可变(mut):
fn main() {
let mut v = vec![1, 2, 3];
// 添加元素到向量末尾
v.push(4);
v.push(5);
println!("updated vector: {:?}", v);
}3. 读取向量中的元素
读取向量元素主要有两种方法:使用索引语法和使用 get 方法。
3.1 使用索引语法
使用索引语法可以直接获取向量中指定位置的元素。
例如:
fn main() {
let v = vec![10, 20, 30, 40, 50];
let third: &i32 = &v[2]; // 注意:索引从 0 开始,所以索引 2 表示第三个元素
println!("the third element is: {}", third);
}注意:如果索引超出向量范围(例如访问一个不存在的元素),使用索引语法会导致程序 panic,从而崩溃。
3.2 使用 get 方法
get 方法会返回一个 option<&t>,在访问超出范围时返回 none 而不是 panic,从而可以通过匹配(match)或其他方式来安全处理这种情况:
fn main() {
let v = vec![10, 20, 30, 40, 50];
// 试图获取索引为 100 的元素
match v.get(100) {
some(value) => println!("the element is: {}", value),
none => println!("there is no element at index 100."),
}
}4. 向量与借用检查器
rust 的借用规则保证了对向量元素的引用安全。
举个例子,如果我们在持有某个元素的不可变引用时尝试修改向量,就会触发借用检查器报错:
fn main() {
let mut v = vec![1, 2, 3];
// 获取第一个元素的不可变引用
let first = &v[0];
// 尝试向向量中添加一个新元素
// v.push(4); // 这行代码会导致编译错误,因为不可变引用和可变操作不能共存
println!("the first element is: {}", first);
}原因在于:向量在内存中是连续存储的,添加新元素可能会导致内存重新分配,进而使已有的引用失效。借用检查器可以在编译期间捕捉到这种潜在的安全问题。
5. 遍历向量
遍历向量通常使用 for 循环。可以选择不可变遍历或者可变遍历以修改元素。
5.1 不可变遍历
下面的代码演示了如何通过不可变引用遍历向量中的每个元素并打印出来:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("the value is: {}", i);
}
}5.2 可变遍历
如果需要修改向量中的每个元素,则可以通过可变引用来遍历:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
// 使用解引用操作符 * 来修改引用指向的值
*i += 50;
}
println!("modified vector: {:?}", v);
}6. 使用枚举存储不同类型的值
向量要求所有元素必须是相同类型的,但在某些情况下,你可能需要在同一个向量中存储不同类型的值。为了解决这一问题,可以定义一个枚举,将所有可能的类型都作为枚举的不同变体,然后将枚举实例存储在向量中:
// 定义一个枚举,表示可能出现的不同类型
enum spreadsheetcell {
int(i32),
float(f64),
text(string),
}
fn main() {
// 创建一个存储 spreadsheetcell 枚举的向量
let row = vec![
spreadsheetcell::int(3),
spreadsheetcell::float(10.12),
spreadsheetcell::text(string::from("blue")),
];
// 遍历向量,并根据每个枚举的变体进行匹配处理
for cell in row {
match cell {
spreadsheetcell::int(value) => println!("integer: {}", value),
spreadsheetcell::float(value) => println!("float: {}", value),
spreadsheetcell::text(text) => println!("text: {}", text),
}
}
}这种方式确保了所有向量中的值都属于同一类型(即枚举类型),同时允许我们存储不同“实际”类型的值,并通过 match 语句在编译时检查每个可能的情况。
7. 向量的内存释放
rust 中的向量在超出作用域后会自动释放,向量中的所有元素也会随之被 drop(销毁)。这一机制确保了内存的自动回收。
例如:
fn main() {
{
let v = vec![1, 2, 3, 4];
// 在这里 v 以及其中的值都是有效的
println!("vector inside scope: {:?}", v);
} // 离开作用域后,v 自动被 drop,内存被释放
// 这里 v 不再有效
}借用检查器同样会确保在向量被 drop 之后,不再存在对其中元素的有效引用。
总结
本文介绍了如何在 rust 中使用向量来存储值列表,包括以下几个方面:
- 创建向量:使用
vec::new创建空向量或使用vec!宏初始化向量,并掌握类型推断与显式注解的区别。 - 更新向量:通过
push方法向向量添加元素,理解可变性的重要性。 - 读取向量元素:比较索引语法和
get方法的优缺点,特别是处理越界访问时的区别。 - 遍历向量:演示如何使用
for循环对向量进行不可变和可变遍历,并说明了使用解引用操作符来修改元素的方式。 - 存储多种类型:通过定义枚举来将不同类型的值统一存储在一个向量中,并利用
match语句在编译时进行检查。 - 向量的释放:说明向量在超出作用域后会自动释放,同时向量中的元素也会被 drop,从而确保内存安全。
向量是 rust 常用且强大的集合类型,熟练掌握其用法能够帮助你编写出既高效又安全的代码。接下来,你还可以继续探索 rust 中其他集合类型(如 string、hashmap 等)的使用方式,进一步提升项目的组织和数据处理能力。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论