Rust 向量(Vec)

Rust 向量是一个长度可变的数组,它使用一段 连续的内存块 存储相同类型的元素。

Rust 向量与数组不同之处在于:向量的长度是可变的,可以在运行时增长或者缩短,而数组的长度是固定不变的。

Rust 向量以特定顺序(添加顺序)将数据存储为元素序列。

向量中的每个元素都分配有唯一的索引号。

索引从 0 开始并自增到 n-1,其中 n 是集合的大小。

例如集合有 5 个元素,那么第一个元素的下标是 0,最后一个元素的下标是 4。

  • 元素添加到向量时会添加到向量的末尾。这个操作类似于 栈 ( stack ),因此可以用来实现 的功能。
  • 向量的内存在 堆 ( heap ) 上存储,因此长度动态可变。

1. Rust 创建向量的语法

Rust 在标准库中定义了结构体 Vec 用于表示一个向量。同时提供了 new() 静态方法用于创建一个结构体 Vec 的实例。

向量的创建语法格式如下:

let mut instance_name = Vec::new();

除了提供 new() 静态方法创建向量之外, Rust 标准库还提供了 vec!() 宏来简化向量的创建。

let vector_name = vec![val1,val2,val3]

结构体 Vec 包含了大量的方法用于操作向量和向量中的元素,我们逻辑几个常见的于下表,并在后面做一个简单的介绍。

方法 签名 说明
new() pub fn new()->Vec 创建一个空的向量的实例
push() pub fn push(&mut self, value: T) 将某个值 T 添加到向量的末尾
remove() pub fn remove(&mut self, index: usize) -> T 删除并返回指定的下标元素。
contains() pub fn contains(&self, x: &T) -> bool 判断向量是否包含某个值
len() pub fn len(&self) -> usize 返回向量中的元素个数

2. 使用 Vec::new() 静态方法创建向量

创建向量的一般通过调用 Vec 结构的 new() 静态方法来创建。

当有了向量的一个实例后,再通过 push() 方法像向量添加元素

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);
   v.push(40);

   println!("size of vector is :{}",v.len());
   println!("{:?}",v);
}

运行以上 Rust 代码,输出结果如下

size of vector is :3
[20, 30, 40]

上面的代码中,我们使用结构体 Vec 提供的静态方法 new() 创建向量的一个实例。

有了向量时候之后,使用 push(val) 方法像实例添加元素。

len() 方法用于获取向量的元素个数。

3. 使用 vec! 宏创建向量

使用 Vec::new() 方法创建一个向量的实例,然后在使用 push() 方法添加元素的操作看起来有点复杂。

为了使创建向量看起来像创建数组那么简单,Rust 标准库提供了 vect! 用于简化向量的创建。

使用 vect! 宏创建向量时,向量的数据类型由第一个元素自动推断出来。

fn main() {
   let v = vec![1,2,3];
   println!("{:?}",v);
}

运行以上 Rust 代码,输出结果如下

[1, 2, 3]

向量也是相同类型元素的集合。

因此,如果给向量传递了不同数据类型的值则会引发错误 error[E0308]: mismatched types 。

下面的代码,编译会报错

fn main() {
   let v = vec![1,2,3,"hello"];
   println!("{:?}",v);
}

错误信息为

error[E0308]: mismatched types
 --> src/main.rs:2:23
  |
2 |    let v = vec![1,2,3,"hello"];
  |                       ^^^^^^^ expected integer, found reference
  |
  = note: expected type `{integer}`
             found type `&'static str`

error: aborting due to previous error

4. 追加元素到向量中 push()

push() 方法可以将指定的值添加到向量的末尾

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);
   v.push(40);

   println!("{:?}",v);
}

运行以上 Rust 代码,输出结果如下

[20, 30, 40]

5. 删除向量中的某个元素 remove()

remove() 方法移除并返回向量中指定的下标索引处的元素,将其后面的所有元素移到向左移动一位。

fn main() {
   let mut v = vec![10,20,30];
   v.remove(1);
   println!("{:?}",v);
}

运行以上 Rust 代码,输出结果如下

[10, 30]

6. 判断向量是否包含某个元素

contains() 用于判断向量是否包含某个值。

如果值在向量中存在则返回 true,否则返回 false。

fn main() {
   let v = vec![10,20,30];
   if v.contains(&10) {
      println!("found 10");
   }
   println!("{:?}",v);
}

运行以上 Rust 代码,输出结果如下

found 10
[10, 20, 30]

7. 获取向量的长度

len() 方法可以获取向量的长度,也就是向量元素的个数。

fn main() {
   let v = vec![1,2,3];
   println!("size of vector is :{}",v.len());
}

运行以上 Rust 代码,输出结果如下

size of vector is :3

8. 访问向量元素的方法

向量既然被称为是可变的数组,那么它的元素当然可以使用 下标 语法来访问。

也就是可以使用 索引号 来访问向量的每一个元素。

例如下面的代码,我们可以使用 v[0] 来访问第一个元素 20,使用 v[1] 来访问第二个元素。

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);

   println!("{:?}",v[0]);
}

运行以上 Rust 代码,输出结果如下

20

9. 迭代/遍历向量

向量本身就实现了迭代器特质,因此可以直接使用 for in 语法来遍历向量

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);
   v.push(40);
   v.push(500);

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

   // println!("{:?}",v); // 运行出错,因为向量已经不可用
}

编译运行以上 Rust 代码,输出结果如下

20
30
40
500

如果把上面代码中的注释去掉,则会报编译错误

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);
   v.push(40);
   v.push(500);

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

   println!("{:?}",v); // 运行出错,因为向量已经不可用
}

编译出错

error[E0382]: borrow of moved value: `v`
  --> src/main.rs:12:20
   |
2  |    let mut v = Vec::new();
   |        ----- move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
...
8  |    for i in v {
   |             - value moved here
...
12 |    println!("{:?}",v); // 运行出错因为向量已经不可用
   |                    ^ value borrowed here after move

出错原因我们在 Rust 所有权 Ownership 章节已经提到过了,这里就不做详细介绍了。

修复的方式,就是在使用使用 for in 来迭代向量的一个引用

fn main() {
   let mut v = Vec::new();
   v.push(20);
   v.push(30);
   v.push(40);
   v.push(500);

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

编译运行以上 Rust 代码,输出结果如下

20
30
40
500
[20, 30, 40, 500]

下一章:Rust 哈希表

Rust 哈希表(HashMap):哈希表 HashMap 就是键值对的集合。哈希表中不允许有重复的键,但允许不同的键有相同的值。哈希表 HashMap 常用于通过键查找对应的值。Rust 语言使用 HashMap 结构体来表示哈希表。HashMap 结构体在 Rust 语言标准库中的 std::collections 模块中定义。使用 HashMap 结构体之前需要显式导入 std::collections 模块。