Witnessは、証明を構築することで存在を証明するパターンです。プログラミングの文脈では、witnessはシステムの特定のプロパティを証明する方法であり、そのプロパティが成り立つ場合にのみ構築できる値を提供することで行います。

Moveにおけるwitness

構造体のセクションで示したように、構造体はそれを定義するモジュールによってのみ作成(またはパック)することができます。したがって、Moveでは、モジュールはそれを構築することによって型の所有権を証明します。これはMoveの最も重要なパターンの1つであり、ジェネリック型のインスタンス化と認可に広く使用されています。

実際には、witnessを使用するためには、引数としてwitnessを期待する関数が必要です。以下の例では、new関数がT型のwitnessを期待してInstance<T>インスタンスを作成します。

witnessの構造体が保存されないことがよくあり、そのため関数はその型に対してDropアビリティを要求することがあります。

module book::witness {
    /// witnessが必要な構造体。
    public struct Instance<T> { t: T }

    /// 提供されたTで`Instance<T>`の新しいインスタンスを作成します。
    public fun new<T>(witness: T): Instance<T> {
        Instance { t: witness }
    }
}

Instance<T>を構築する唯一の方法は、T型のインスタンスでnew関数を呼び出すことです。これはMoveにおけるwitnessパターンの基本的な例です。witnessを提供するモジュールには、以下のbook::witness_sourceモジュールのような対応する実装がしばしばあります:

module book::witness_source {
    use book::witness::{Self, Instance};

    /// witnessとして使用される構造体。
    public struct W {}

    /// `Instance<W>`の新しいインスタンスを作成します。
    public fun new_instance(): Instance<W> {
        witness::new(W {})
    }
}

W構造体のインスタンスがnew_instance関数に渡されてInstance<W>を作成し、それによってbook::witness_sourceモジュールがW型を所有していることを証明しています。

ジェネリック型のインスタンス化

witnessを使用すると、ジェネリック型を具体的な型でインスタンス化できます。これは、型に関連する動作を継承し、モジュールがその機能を提供する場合には拡張するオプションを持つのに役立ちます。

// ファイル: [sui-フレームワーク/sources/balance.move](<https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/balance.move>)
/// Tの供給。ミントとバーンに使用されます。
public struct Supply<phantom T> has key, store {
    id: UID,
    value: u64
}

/// 提供されたwitnessを使用して、T型の新しい供給を作成します。
public fun create_supply<T: drop>(_w: T): Supply<T> {
    Supply { value: 0 }
}

/// `Supply`の値を取得します。
public fun supply_value<T>(supply: &Supply<T>): u64 {
    supply.value
}

上記の例(Suiフレームワークbalanceモジュールから借用)では、SupplyT型のwitnessを提供することでのみ構築できるジェネリック構造体です。witnessは値で取られ、破棄されます - したがって、Tdropアビリティを持つ必要があります。

インスタンス化されたSupply<T>は、その後、新しいBalance<T>をミントするために使用できます。ここで、Tは供給の型です。

// ファイル: [sui-フレームワーク/sources/balance.move](<https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/sui-framework/sources/balance.move>)
/// 保存可能な残高。
struct Balance<phantom T> has store {
    value: u64
}

/// 供給を`value`だけ増やし、この値で新しい`Balance<T>`を作成します。
public fun increase_supply<T>(self: &mut Supply<T>, value: u64): Balance<T> {
    assert!(value < (18446744073709551615u64 - self.value), EOverflow);
    self.value = self.value + value;
    Balance { value }
}

One Time Witness(一回限りのwitness)

構造体は何度でも作成できますが、構造体が一度だけ作成されることを保証する必要がある場合があります。この目的のために、Suiは「One-Time Witness」- 一度だけ使用できる特別なwitness - を提供しています。これについては次のセクションでより詳しく説明します。

まとめ