Skip to content

1. 什么是vector

向量Vec<T>用于存储一系列的值,默认情况下向量只能存储同一数据类型的值。所有值在内存中彼此相邻排列。

2. vector的基本操作

1. 创建vector

  1. 使用宏创建,并指定初始值。通常rust会自行推断vec<T>的类型

    rust
    let v = vec![1,2,3]; //推断出 v 的类型是 Vec<i32>
  2. 使用Vec::new()方法创建空vector

    rust
    let v:Vec<i32> = Vec::new();//使用该方式创建vector是需要进行类型标注

2. 更新vector元素

对于空的vector使用push向其中添加元素,后续使用索引更新元素,注意声明其为可变mut。

rust
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方法。

rust
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。

rust
fn main(){
    let mut v = vec![1,2,3,4];
    
    let x  = &v[100];
  	//let x = v.get(100);

    println!(
        "{:?}",x
    )
}
shell
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
shell
//替换注释行后执行
None

注意:

当作用域内仍然存在对vector(使用vec!创建的vector)的引用时,尝试添加元素后再使用该引用,会导致error。下面代码块的运行结果:

rust
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`.
rust
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。

rust
fn main(){
    let mut v = vec![1,2,3,4];
    
    v.remove(100);

    println!(
        "{:?}",v
    )
}
shell
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 backtrace

5. 遍历vector

当需要逐一访问vector元素时,使用for循环,而不用一个个用索引或get访问。

rust
//使用for循环获取每个元素的不可变引用并打印它们
let v = vec![1,2,3];

for i in &v{
  println!("{}",i)
}

当需要访问并对元素作出修改时,对mut vector进行可变引用的for循环遍历

rust
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实现这个需求。

rust
#[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")]
}