Skip to content

泛型

泛型是一种允许类型或函数与多种类型配合使用的机制。当需要编写能够处理不同类型的函数,或定义可以容纳任意类型的结构时,泛型非常有用。泛型是 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 };
}