这是关于Move语言中向量(vector)类型的详细介绍。我会将其翻译成简单易懂的中文,同时保留关键的技术术语:

向量

vector<T>是Move提供的唯一原始集合类型。vector<T>T类型元素的同类集合,可以通过在"末端"推入/弹出值来增长或缩小。

vector<T>可以用任何类型T实例化。例如,vector<u64>,vector<address>,vector<0x42::my_module::MyData>,和vector<vector<u8>>都是有效的向量类型。

字面量

通用vector字面量

任何类型的向量都可以用vector字面量创建。

语法类型描述
vector[]vector[]: vector<T>,其中T是任何单一的非引用类型空向量
vector[e1, ..., en]vector[e1, ..., en]: vector<T>,其中e_i: T0 < i <= nn > 0n个元素的向量(长度为n)

在这些情况下,vector的类型是从元素类型或向量的使用中推断出来的。如果无法推断类型,或者为了更清晰,可以显式指定类型:

vector<T>[]: vector<T>
vector<T>[e1, ..., en]: vector<T>

向量字面量示例

(vector[]: vector<bool>);
(vector[0u8, 1u8, 2u8]: vector<u8>);
(vector<u128>[]: vector<u128>);
(vector<address>[@0x42, @0x100]: vector<address>);

vector<u8>字面量

Move中向量的一个常见用例是表示"字节数组",用vector<u8>表示。这些值通常用于加密目的,如公钥或哈希结果。这些值非常常见,以至于提供了特定的语法使值更易读,而不是必须使用vector[]来指定每个单独的u8值。

目前支持两种类型的vector<u8>字面量,字节字符串_和_十六进制字符串

字节字符串

字节字符串是带有b前缀的带引号字符串字面量,例如b"Hello!\n"

这些是ASCII编码的字符串,允许使用转义序列。目前,支持的转义序列有:

转义序列描述
\n换行(或换行符)
\r回车
\t制表符
\\反斜杠
\0空字符
\"引号
\xHH十六进制转义,插入十六进制字节序列HH

十六进制字符串

十六进制字符串是带有x前缀的带引号字符串字面量,例如x"48656C6C6F210A"

每个字节对,范围从00FF,被解释为十六进制编码的u8值。所以每个字节对对应结果vector<u8>中的一个条目。

字符串字面量示例

fun byte_and_hex_strings() {
    assert!(b"" == x"", 0);
    assert!(b"Hello!\n" == x"48656C6C6F210A", 1);
    assert!(b"\x48\x65\x6C\x6C\x6F\x21\x0A" == x"48656C6C6F210A", 2);
    assert!(
        b"\"Hello\tworld!\"\n \r \\Null=\0" ==
            x"2248656C6C6F09776F726C6421220A200D205C4E756C6C3D00",
        3
    );
}

操作

vector通过Move标准库中的std::vector模块支持以下操作:

函数描述是否中止?
vector::empty<T>(): vector<T>创建一个可以存储T类型值的空向量从不
vector::singleton<T>(t: T): vector<T>创建一个包含t的大小为1的向量从不
vector::push_back<T>(v: &mut vector<T>, t: T)t添加到v的末尾从不
vector::pop_back<T>(v: &mut vector<T>): T移除并返回v中的最后一个元素如果v为空
vector::borrow<T>(v: &vector<T>, i: u64): &T返回索引i处的T的不可变引用如果i不在范围内
vector::borrow_mut<T>(v: &mut vector<T>, i: u64): &mut T返回索引i处的T的可变引用如果i不在范围内
vector::destroy_empty<T>(v: vector<T>)删除v如果v不为空
vector::append<T>(v1: &mut vector<T>, v2: vector<T>)v2中的元素添加到v1的末尾从不
vector::contains<T>(v: &vector<T>, e: &T): bool如果e在向量v中返回true。否则,返回false从不
vector::swap<T>(v: &mut vector<T>, i: u64, j: u64)交换向量v中第i和第j个索引处的元素如果ij超出范围
vector::reverse<T>(v: &mut vector<T>)原地反转向量v中元素的顺序从不
vector::index_of<T>(v: &vector<T>, e: &T): (bool, u64)如果e在索引i处的向量v中,返回(true, i)。否则,返回(false, 0)从不
vector::remove<T>(v: &mut vector<T>, i: u64): T移除向量v的第i个元素,移动所有后续元素。这是O(n)操作,并保持向量中元素的顺序如果i超出范围
vector::swap_remove<T>(v: &mut vector<T>, i: u64): T将向量v的第i个元素与最后一个元素交换,然后弹出该元素。这是O(1)操作,但不保持向量中元素的顺序如果i超出范围

随着时间的推移,可能会添加更多操作。

示例

use std::vector;

let mut v = vector::empty<u64>();
vector::push_back(&mut v, 5);
vector::push_back(&mut v, 6);

assert!(*vector::borrow(&v, 0) == 5, 42);
assert!(*vector::borrow(&v, 1) == 6, 42);
assert!(vector::pop_back(&mut v) == 6, 42);
assert!(vector::pop_back(&mut v) == 5, 42);

销毁和复制vector

vector<T>的某些行为取决于元素类型T的能力。例如,包含没有drop能力的元素的向量不能像上面示例中的v那样被隐式丢弃--它们必须使用vector::destroy_empty显式销毁。

注意,除非vec包含零个元素,否则vector::destroy_empty将在运行时中止:

fun destroy_any_vector<T>(vec: vector<T>) {
    vector::destroy_empty(vec) // 删除这行将导致编译器错误
}

但对于丢弃包含具有drop能力的元素的向量不会发生错误:

fun destroy_droppable_vector<T: drop>(vec: vector<T>) {
    // 有效!
    // 不需要显式做任何事来销毁向量
}

同样,除非元素类型具有copy能力,否则向量不能被复制。换句话说,当且仅当T具有copy能力时,vector<T>才具有copy能力。请注意,如果需要,它将被隐式复制:

let x = vector[10];
let y = x; // 隐式复制
let z = x;
(y, z)

请记住,复制大向量可能很昂贵。如果这是一个问题,注释intended用法可以防止意外复制。例如,

let x = vector[10];
let y = move x;
let z = x; // 错误! x已被移动
(y, z)

有关更多详细信息,请参阅类型能力泛型部分。

所有权

上文所述,只有当元素可以被复制时,vector值才能被复制。在这种情况下,可以通过copy解引用*进行复制。