Move コンパイラは、レシーバー構文をサポートしています。これにより、構造体のインスタンスで呼び出すことができるメソッドを定義できます。これは、他のプログラミング言語のメソッド構文に似ています。構造体のフィールドを操作する関数を定義する便利な方法です。
関数の最初の引数がモジュール内部の構造体である場合、その関数は .
演算子を使用して呼び出すことができます。関数が別のモジュールの構造体を使用する場合、デフォルトではメソッドは構造体に関連付けられません。この場合、関数は標準の関数呼び出し構文を使用して呼び出すことができます。
モジュールがインポートされると、メソッドは自動的に構造体に関連付けられます。
module book::hero {
/// ヒーローを表す構造体。
public struct Hero has drop {
health: u8,
mana: u8,
}
/// 新しいヒーローを作成する。
public fun new(): Hero { Hero { health: 100, mana: 100 } }
/// マナを消費して呪文を唱えるメソッド。
public fun heal_spell(hero: &mut Hero) {
hero.health = hero.health + 10;
hero.mana = hero.mana - 10;
}
/// ヒーローの体力を返すメソッド。
public fun health(hero: &Hero): u8 { hero.health }
/// ヒーローのマナを返すメソッド。
public fun mana(hero: &Hero): u8 { hero.mana }
#[test]
// `Hero` 構造体のメソッドをテストする。
fun test_methods() {
let mut hero = new();
hero.heal_spell();
assert!(hero.health() == 110, 1);
assert!(hero.mana() == 90, 2);
}
}
複数の構造体とそのメソッドを定義するモジュールの場合、名前の競合を避けたり、構造体により適切な名前のメソッドを提供したりするために、メソッドエイリアスを定義することができます。
エイリアスの構文は以下の通りです:
// ローカルメソッド関連付け
use fun function_path as Type.method_name;
// エクスポートされたエイリアス
public use fun function_path as Type.method_name;
パブリックエイリアスは、同じモジュールで定義された構造体に対してのみ許可されます。構造体が別のモジュールで定義されている場合でも、エイリアスを作成することはできますが、パブリックにすることはできません。
以下の例では、hero
モジュールを変更し、Villain
という別の型を追加しました。Hero
と Villain
は似たようなフィールド名とメソッドを持っています。名前の競合を避けるために、メソッドにはそれぞれ hero_
と villain_
というプレフィックスを付けています。しかし、これらのメソッドのエイリアスを作成することで、プレフィックスなしで構造体のインスタンスで呼び出すことができます。
module book::hero_and_villain {
/// ヒーローを表す構造体。
public struct Hero has drop {
health: u8,
}
/// 悪役を表す構造体。
public struct Villain has drop {
health: u8,
}
/// 新しいHeroを作成する。
public fun new_hero(): Hero { Hero { health: 100 } }
/// 新しいVillainを作成する。
public fun new_villain(): Villain { Villain { health: 100 } }
// `hero_health` メソッドのエイリアス。
// モジュールがインポートされると自動的にインポートされる。
public use fun hero_health as Hero.health;
public fun hero_health(hero: &Hero): u8 { hero.health }
// `villain_health` メソッドのエイリアス。
// モジュールがインポートされると自動的にインポートされる。
public use fun villain_health as Villain.health;
public fun villain_health(villain: &Villain): u8 { villain.health }
#[test]
// `Hero` と `Villain` 構造体のメソッドをテストする。
fun test_associated_methods() {
let hero = new_hero();
assert!(hero.health() == 100, 1);
let villain = new_villain();
assert!(villain.health() == 100, 3);
}
}
ご覧のように、テスト関数では、プレフィックスなしで Hero と Villain のインスタンスに対して health メソッドを呼び出しています。コンパイラは自動的にメソッドを構造体に関連付けます。
現在のモジュールの構造体に、別のモジュールで定義された関数を関連付けることも可能です。同じアプローチに従って、別のモジュールで定義されたメソッドのエイリアスを作成できます。標準ライブラリの bcs::to_bytes
メソッドを使用し、Hero
構造体に関連付けてみましょう。これにより、Hero
構造体をバイトのベクトルにシリアライズできるようになります。
// TODO: より良い例(外部モジュール...)
module book::hero_to_bytes {
// `bcs::to_bytes` メソッドのエイリアス。
// インポートされたエイリアスはモジュールの先頭で定義する必要がある。
// public use fun bcs::to_bytes as Hero.to_bytes;
/// ヒーローを表す構造体。
public struct Hero has drop {
health: u8,
mana: u8,
}
/// 新しいヒーローを作成する。
public fun new(): Hero { Hero { health: 100, mana: 100 } }
#[test]
// `Hero` 構造体のメソッドをテストする。
fun test_hero_serialize() {
// let mut hero = new();
// let serialized = hero.to_bytes();
// assert!(serialized.length() == 3, 1);
}
}