1. 什么是vector
向量Vec<T>用于存储一系列的值,默认情况下向量只能存储同一数据类型的值。所有值在内存中彼此相邻排列。
2. vector的基本操作
1. 创建vector
使用宏创建,并指定初始值。通常rust会自行推断
vec<T>的类型rustlet v = vec![1,2,3]; //推断出 v 的类型是 Vec<i32>使用Vec::new()方法创建空vector
rustlet v:Vec<i32> = Vec::new();//使用该方式创建vector是需要进行类型标注
2. 更新vector元素
对于空的vector使用push向其中添加元素,后续使用索引更新元素,注意声明其为可变mut。
let mut z = Vec::new();
let mut v = vec![1,2,3];
z.push(8);
z.push(9);
z.push(10);
println!("{:?}",z) // [8,9,10]
z[0] = 7;
v[0] = 5;
println!("{:?}",z) // [7,9,10]
println!("{:?}",v) // [5,2,3]3. 读取vector元素
有两种方法读取vector中的元素:索引 和 get方法。
fn main(){
let mut v = vec![1,2,3,4];
let x = &v[0];
let z = v.get(0);
println!(
"{:?},{:?}",x,z //1,Some(1)
)
}可以看出get方法返回的是一个Option<T>,其相较于 引用+索引访问的优点是访问超出边界索引的情况。示例vector最大索引是3(索引从0开始),倘若访问v[100],引用 +索引的方式将直接使程序panic,而get则返回None,程序不会panic。
fn main(){
let mut v = vec![1,2,3,4];
let x = &v[100];
//let x = v.get(100);
println!(
"{:?}",x
)
}thread 'main' panicked at code.rs:4:16:
index out of bounds: the len is 4 but the index is 100
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace//替换注释行后执行
None注意:
当作用域内仍然存在对vector(使用vec!创建的vector)的引用时,尝试添加元素后再使用该引用,会导致error。下面代码块的运行结果:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> code.rs:6:5
|
4 | let x = &v[0];
| - immutable borrow occurs here
5 |
6 | v.push(5);
| ^^^^^^^^^ mutable borrow occurs here
...
9 | "{:?}",x
| - immutable borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0502`.fn main(){
let mut v = vec![1,2,3,4];
let x = &v[0];
v.push(5);
println!(
"{:?}",x
)
}之所以发生这个问题,是因为借用检查器在避免特殊情况写可能遇到的无法访问的问题。在 vector 的结尾增加新元素时,加入在没有足够空间将所有元素依次相邻存放的情况下,可能会要求分配新内存并将旧元素拷贝到新的空间中。这时,第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。
4. 删除vector元素
使用remove方法,移除指定索引位置的元素。当超出vector索引长度的边界时,不同于get方法的不会导致程序panic,其会导致程序panic。
fn main(){
let mut v = vec![1,2,3,4];
v.remove(100);
println!(
"{:?}",v
)
}thread 'main' panicked at code.rs:4:7:
removal index (is 100) should be < len (is 4)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace5. 遍历vector
当需要逐一访问vector元素时,使用for循环,而不用一个个用索引或get访问。
//使用for循环获取每个元素的不可变引用并打印它们
let v = vec![1,2,3];
for i in &v{
println!("{}",i)
}当需要访问并对元素作出修改时,对mut vector进行可变引用的for循环遍历
let mut v = vec![1,2,3];
for i in &mut v{
*i += 10;
}
println!("{}",v) // [11,12,13]注意
为了修改可变引用所指向的值,在使用 += 运算符之前必须使用解引用运算符(*)获取 i 中的值。
vec标准库还拥有许多操作vector的方法:如pop等
3. 使用枚举实现vector存储非同一数据类型元素
实际应用场景下,一定存在需要在连续内存中存储不同类型值的需求。vector可以借助enum实现这个需求。
#[derive(Debug)]
#[allow(dead_code)]
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
fn main(){
let mut v:Vec<SpreadsheetCell> = Vec::new();
v.push(SpreadsheetCell::Int(1));
v.push(SpreadsheetCell::Float(0.12));
v.push(SpreadsheetCell::Text(String::from("hello")));
println!("{:?}",v) //[Int(1), Float(0.12), Text("hello")]
}