结构体方法
Move 编译器支持_接收者语法_,允许在结构体实例上定义可调用的方法。这类似于其他编程语言中的方法语法。这是一种方便的方式,可以在结构体的字段上定义操作。
方法语法
如果函数的第一个参数是模块内部的结构体,则可以使用 .
运算符调用该函数。如果函数使用另一个模块中的结构体,则默认不会将方法与结构体关联起来。在这种情况下,可以使用标准的函数调用语法来调用该函数。
当导入一个模块时,方法会自动与结构体关联起来。
module book::hero {
/// A struct representing a hero.
public struct Hero has drop {
health: u8,
mana: u8,
}
/// Create a new Hero.
public fun new(): Hero { Hero { health: 100, mana: 100 } }
/// A method which casts a spell, consuming mana.
public fun heal_spell(hero: &mut Hero) {
hero.health = hero.health + 10;
hero.mana = hero.mana - 10;
}
/// A method which returns the health of the hero.
public fun health(hero: &Hero): u8 { hero.health }
/// A method which returns the mana of the hero.
public fun mana(hero: &Hero): u8 { hero.mana }
#[test]
// Test the methods of the `Hero` struct.
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 {
/// A struct representing a hero.
public struct Hero has drop {
health: u8,
}
/// A struct representing a villain.
public struct Villain has drop {
health: u8,
}
/// Create a new Hero.
public fun new_hero(): Hero { Hero { health: 100 } }
/// Create a new Villain.
public fun new_villain(): Villain { Villain { health: 100 } }
// Alias for the `hero_health` method. Will be imported automatically when
// the module is imported.
public use fun hero_health as Hero.health;
public fun hero_health(hero: &Hero): u8 { hero.health }
// Alias for the `villain_health` method. Will be imported automatically
// when the module is imported.
public use fun villain_health as Villain.health;
public fun villain_health(villain: &Villain): u8 { villain.health }
#[test]
// Test the methods of the `Hero` and `Villain` structs.
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: better example (external module...)
module book::hero_to_bytes {
// Alias for the `bcs::to_bytes` method. Imported aliases should be defined
// in the top of the module.
// public use fun bcs::to_bytes as Hero.to_bytes;
/// A struct representing a hero.
public struct Hero has drop {
health: u8,
mana: u8,
}
/// Create a new Hero.
public fun new(): Hero { Hero { health: 100, mana: 100 } }
#[test]
// Test the methods of the `Hero` struct.
fun test_hero_serialize() {
// let mut hero = new();
// let serialized = hero.to_bytes();
// assert!(serialized.length() == 3, 1);
}
}
进一步阅读
- 在 Move 参考中的 方法语法。