Witnessは、証明を構築することで存在を証明するパターンです。プログラミングの文脈では、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
モジュールから借用)では、Supply
はT
型のwitnessを提供することでのみ構築できるジェネリック構造体です。witnessは値で取られ、破棄されます - したがって、T
はdropアビリティを持つ必要があります。
インスタンス化された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 }
}
構造体は何度でも作成できますが、構造体が一度だけ作成されることを保証する必要がある場合があります。この目的のために、Suiは「One-Time Witness」- 一度だけ使用できる特別なwitness - を提供しています。これについては次のセクションでより詳しく説明します。