我们将首先看一下 Vec<T>
,也称为向量的集合类型。向量允许您在单个数据结构中存储多个值,将所有值都放在内存中的相邻位置。向量只能存储相同类型的值。当您有一个项目列表时,例如文件中的文本行或购物车中商品的价格时,它们非常有用。
Vec<T>
包含在标准库预导 中,这意味着无需手动导入它。
要创建一个新的空向量,我们调用 Vec::new
函数,如下所示:
let v: Vec<u64> = Vec::new();
请注意,这里我们添加了一个类型注释。因为我们没有向该向量插入任何值,所以 Sway 编译器不知道我们打算存储什么类型的元素。向量使用泛型实现,这意味着标准库提供的 Vec<T>
类型可以容纳任何类型。当我们创建一个用于保存特定类型的向量时,我们可以在尖括号内指定类型。在上面的示例中,我们告诉 Sway 编译器 v
中的 Vec<T>
将保存 u64
类型的元素。
要创建一个向量,然后向其中添加元素,我们可以使用 push
方法,如下所示:
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
与任何变量一样,如果我们希望能够更改其值,我们需要使用 mut
关键字使其可变,如 声明一个变量 部分所讨论的。我们放置在其中的数字都是 u64
类型,Sway 编译器从数据中推断出这一点,因此我们不需要 Vec<u64>
注释。
要读取向量中特定索引处存储的值,可以使用 get
方法,如下所示:
let third = v.get(2);
match third {
Some(third) => log(third),
None => revert(42),
}
请注意两个细节。首先,我们使用索引值 2
来获取第三个元素,因为向量是按数字索引的,从零开始。其次,我们使用传递给 get
的索引作为参数来获取第三个元素,这给了我们一个 Option<T>
。
当 get
方法传递一个超出向量范围的索引时,它会返回 None
而不会发生恐慌。这在正常情况下偶尔会发生超出向量范围的元素访问时特别有用。您的代码将处理 Some(element)
或 None
的逻辑。例如,索引可以作为合同方法参数传递。如果传递的参数太大,方法 get
将返回一个 None
值,然后合同方法可能决定在发生这种情况时恢复,或者返回一个有意义的错误,告诉用户当前向量中有多少项,并给他们另一个机会传递有效的值。
要依次访问向量中的每个元素,我们将使用 while
循环和 len
方法遍历所有有效的索引,如下所示:
let mut i = 0;
while i < v.len() {
log(v.get(i).unwrap());
i += 1;
}
请注意两个细节。首先,我们使用 len
方法返回向量的长度。其次,我们调用 unwrap
方法来提取 get
返回的 Option
。我们知道 unwrap
不会失败(即不会导致回滚),因为传递给 get
的每个索引 i
都已知小于向量的长度。
向量只能存储相同类型的值。这可能不方便;肯定有需要存储不同类型的项目列表的用例。幸运的是,枚举的变体在同一枚举类型下定义,因此当我们需要一个类型来表示不同类型的元素时,我们可以定义和使用一个枚举!
例如,假设我们要从表中的一行获取值,其中一些列包含整数,一些包含 b256
值,一些包含布尔值。我们可以定义一个枚举,其变体将保存不同的值类型,所有枚举变体都将被视为相同的类型:即枚举类型。然后我们可以创建一个向量来保存该枚举,因此,最终会保存不同的类型。我们已经在下面演示了这一点:
enum TableCell {
Int: u64,
B256: b256,
Boolean: bool,
}
let mut row = Vec::new();
row.push(TableCell::Int(3));
row.push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101));
row.push(TableCell::Boolean(true));
现在我们已经讨论了一些使用向量的常见方法,请务必查看标准库中 Vec<T>
定义的所有许多有用方法的 API 文档。目前,这些可以在 source code for Vec<T>
中找到。例如,除了 push
之外,pop
方法会移除并返回最后一个元素,remove
方法会移除并返回向量中某个选择的索引处的元素,insert
方法会在向量中的某个选择的索引处插入元素等。