Skip to content

向量

向量是 Move 中用于存储动态大小元素集合的内建方式。它们类似于其他编程语言中的动态数组,但具有 Move 的类型安全和能力限制。向量是 Move 标准库的重要组成部分,支持多种高效操作。

向量语法

向量的类型通过 vector 关键字定义,其元素类型写在尖括号 <...> 中。向量的元素可以是任何有效的 Move 类型,包括基本类型、结构体,甚至其他向量。

定义和初始化向量

  • 空向量 使用 vector[] 初始化空向量。元素类型必须明确指定,或者通过上下文推断。
move
let empty: vector<bool> = vector[]; // 空布尔向量
  • 非空向量 使用 vector[...] 初始化带有初始值的向量。
move
let v: vector<u8> = vector[1, 2, 3]; // 包含 u8 元素的向量
  • 嵌套向量 向量的元素可以是其他向量。
move
let vv: vector<vector<u8>> = vector[vector[1, 2], vector[3, 4]]; // 二维向量

类型推断

如果上下文能够推断出元素类型,可以省略显式类型声明:

move
let v = vector[1, 2, 3]; // 推断为 vector<u8>

向量操作

Move 标准库的 std::vector 模块提供了操作向量的函数。这些操作包括:

  1. 追加元素:push_back 将一个新元素添加到向量的末尾。
move
let mut v = vector[10, 20];
v.push_back(30); // v = vector[10, 20, 30]
  1. 移除元素:pop_back 从向量末尾移除一个元素,并返回该元素。如果向量为空,则会触发运行时错误。
move
let mut v = vector[10, 20, 30];
let last = v.pop_back(); // last = 30, v = vector[10, 20]
  1. 获取长度:length 返回向量中元素的数量。
move
let v = vector[10, 20, 30];
assert!(v.length() == 3);
  1. 检查空向量:is_empty 如果向量为空,返回 true
move
let v = vector[];
assert!(v.is_empty());
  1. 移除指定位置元素:remove 删除指定索引的元素,后续元素前移填补空缺。
move
let mut v = vector[10, 20, 30];
let removed = v.remove(1); // removed = 20, v = vector[10, 30]
  1. 销毁空向量:destroy_empty 对于没有 drop 能力的类型,必须显式调用 destroy_empty 来销毁空向量。
move
let v: vector<u8> = vector[];
v.destroy_empty();

注意事项

销毁不可丢弃类型向量

如果向量的元素类型不具备 drop 能力,那么即使是空向量,也不能直接忽略。必须显式调用 destroy_empty

move
public struct NoDrop {} // 没有 `drop` 能力

#[test]
fun test_destroy_empty() {
    let v: vector<NoDrop> = vector[]; // 创建空向量
    v.destroy_empty(); // 必须显式销毁
}

示例:完整向量操作

以下是综合使用向量的示例:

move
#[test]
fun test_vector_operations() {
    let mut v: vector<u8> = vector[1, 2, 3];
    assert!(v.length() == 3);

    v.push_back(4); // 添加元素
    assert!(v.pop_back() == 4); // 移除并返回末尾元素

    let removed = v.remove(1); // 移除第二个元素
    assert!(removed == 2);

    assert!(v.length() == 2);
    assert!(!v.is_empty());
}

扩展:嵌套向量

对于嵌套向量,操作与单层向量一致,但需要注意嵌套层级:

move
#[test]
fun test_nested_vector() {
    let mut vv: vector<vector<u8>> = vector[vector[1, 2], vector[3, 4]];
    vv[1].push_back(5); // 向第二个子向量添加元素
    assert!(vv[1] == vector[3, 4, 5]);
}

性能和能力限制

  1. 动态大小 向量支持动态大小调整,但需要注意每次操作可能涉及内存重新分配,影响性能。
  2. 类型安全 向量的类型必须一致,无法存储不同类型的元素。
  3. 能力限制 Move 编译器会根据元素类型的能力限制(如 copydrop),对向量操作施加约束。例如,没有 drop 能力的类型无法隐式销毁。