泛型
泛型是一种允许类型或函数与多种类型配合使用的机制。当需要编写能够处理不同类型的函数,或定义可以容纳任意类型的结构时,泛型非常有用。泛型是 Move 中许多高级功能的基础,例如集合和抽象实现。
在标准库中的泛型
Move 标准库中提供了一些泛型类型,例如 向量类型和 Option 类型。 向量是一种可容纳任意其他类型的容器,而 Option 用于表示可能存在或不存在的值。
泛型语法
定义泛型类型或函数时,需要在尖括号(<>)中指定泛型参数列表。多个泛型参数之间用逗号分隔。
move
/// 一个可容纳任何类型 `T` 的容器。
public struct Container<T> has drop {
value: T,
}
/// 使用泛型值 `T` 创建新的 `Container`。
public fun new<T>(value: T): Container<T> {
Container { value }
}
上例中,Container 是一个泛型类型,具有单个类型参数 T,其字段 value 存储类型为 T 的值。new 是泛型函数,接受一个 T 类型的值并返回一个 Container<T>
实例。泛型类型在实例化时必须使用具体类型,泛型函数在调用时也需要具体类型。
move
#[test]
fun test_container() {
// 以下三种写法是等价的:
let container: Container<u8> = new(10); // 类型推断
let container = new<u8>(10); // 显式指定类型
let container = new(10u8); // 使用类型标注的字面量
assert!(container.value == 10, 0x0);
// 忽略结构体字段,仅当类型具有 `drop` 能力时才允许。
let Container { value: _ } = container;
}
在测试函数中演示了三种创建 Container<u8>
的方法,并展示了如何解构该结构体。
多个类型参数
可以定义具有多个类型参数的类型或函数。这些类型参数用逗号分隔。
move
/// 一个包含任意类型 `T` 和 `U` 的值对。
public struct Pair<T, U> {
first: T,
second: U,
}
/// 创建新的 `Pair`。
public fun new_pair<T, U>(first: T, second: U): Pair<T, U> {
Pair { first, second }
}
在上述例子中,Pair 是一个具有两个类型参数的泛型类型,new_pair 是一个泛型函数。注意类型参数的顺序需要与声明中的顺序一致。
move
#[test]
fun test_pair() {
// 以下三种写法是等价的:
let pair_1: Pair<u8, bool> = new_pair(10, true); // 类型推断
let pair_2 = new_pair<u8, bool>(10, true); // 显式指定类型
let pair_3 = new_pair(10u8, true); // 使用类型标注的字面量
assert!(pair_1.first == 10, 0x0);
assert!(pair_1.second, 0x0);
// 解构结构体
let Pair { first: _, second: _ } = pair_1;
}
若交换类型参数的顺序,将无法进行类型匹配。
move
#[test]
fun test_swap_type_params() {
let pair1: Pair<u8, bool> = new_pair(10u8, true);
let pair2: Pair<bool, u8> = new_pair(true, 10u8);
// 无法直接比较
// assert!(pair1 == pair2, 0x0);
let Pair { first: pf1, second: ps1 } = pair1;
let Pair { first: pf2, second: ps2 } = pair2;
assert!(pf1 == ps2, 0x0); // 10 == 10
assert!(ps1 == pf2, 0x0); // true == true
}
幻影类型参数
幻影类型参数指未直接用于字段或方法的类型参数。它通常用于标识或约束不同类型的行为。
move
/// 一个具有幻影类型参数的结构体。
public struct Coin<phantom T> {
value: u64
}
Coin 使用幻影类型参数来区分不同的硬币类型。
move
public struct USD {}
public struct EUR {}
#[test]
fun test_phantom_type() {
let coin1: Coin<USD> = Coin { value: 10 };
let coin2: Coin<EUR> = Coin { value: 20 };
let Coin { value: _ } = coin1;
let Coin { value: _ } = coin2;
}
对类型参数的约束
可以通过 T: <ability> + <ability>
语法为泛型类型参数指定能力约束。例如:
move
/// 类型参数需要具有 `drop` 能力。
public struct Droppable<T: drop> {
value: T,
}
/// 类型参数需要同时具有 `copy` 和 `drop` 能力。
public struct CopyableDroppable<T: copy + drop> {
value: T,
}
Move 编译器会检查类型参数是否满足指定能力。
move
/// 没有任何能力的类型。
public struct NoAbilities {}
#[test]
fun test_constraints() {
// 错误:`NoAbilities` 没有 `drop` 能力
// let droppable = Droppable<NoAbilities> { value: 10 };
// 错误:`NoAbilities` 没有 `copy` 和 `drop` 能力
// let copyable_droppable = CopyableDroppable<NoAbilities> { value: 10 };
}