友元
friend 语法用于声明当前模块信任的模块。受信任的模块被允许调用当前模块中标记为public(friend) 可见性的任何函数。有关函数可见性的详细信息,请参阅函数中的可见性部分。
友元声明
模块可以通过友元声明语句将其他模块声明为友元,格式如下:
friend <address::name>— 使用完全限定的模块名称进行友元声明,如下例所示,或者
module 0x42::a {
friend 0x42::b;
}friend <module-name-alias>— 使用模块名称别名进行友元声明,其中模块别名是通过use语句引入的。
module 0x42::a {
use 0x42::b;
friend b;
}一个模块可以有多个友元声明,所有友元模块的并集形成友元列表。在下面的例子中,0x42::B和0x42::C都被视为0x42::A的友元。
module 0x42::a {
friend 0x42::b;
friend 0x42::c;
}与use语句不同,friend只能在模块作用域内声明,不能在表达式块作用域内声明。friend声明可以位于任何顶层结构(例如use、function、struct等)允许的位置。然而,为了可读性,建议将友元声明放在模块定义的开头附近。
请注意,友元概念不适用于Move脚本:
- Move 脚本不能声明
friend模块,因为这样做没有意义:没有机制可以调用脚本中定义的函数。 - Move 模块也不能声明
friend脚本,因为脚本是短暂的代码片段,永远不会发布到全局存储中。
友元声明规则
友元声明受以下规则的约束:
- 一个模块不能声明自己为友元。
module 0x42::m {
friend Self; // ERROR!
// ^^^^ Cannot declare the module itself as a friend
}- 友元模块必须为编译器所知
module 0x42::m {
friend 0x42::nonexistent; // ERROR!
// ^^^^^^^^^^^^^^^^^ Unbound module '0x42::nonexistent'
}- 友元模块必须在相同的账户地址内。(注意:这不是技术要求,而是可能稍后放宽的政策决定。)
module 0x42::m {}
module 0x43::n {
friend 0x42::m; // ERROR!
// ^^^^^^^ Cannot declare modules out of the current address as a friend
}- 友元关系不能创建循环模块依赖。
不允许在友元关系中存在循环,例如0x2::a友元0x2::b友元0x2::c友元0x2::a的关系是不允许的。更一般地说,声明一个友元模块会向当前模块添加对友元模块的依赖(因为目的是让友元在当前模块中调用函数)。如果那个友元模块已经被使用,无论是直接还是间接,就会创建依赖循环。
address 0x2 {
module a {
use 0x2::c;
friend 0x2::b;
public fun a() {
c::c()
}
}
module b {
friend 0x2::c; // ERROR!
// ^^^^^^ This friend relationship creates a dependency cycle: '0x2::b' is a friend of '0x2::a' uses '0x2::c' is a friend of '0x2::b'
}
module c {
public fun c() {}
}
}- 一个模块的友元列表不能包含重复项。
address 0x42 {
module a {}
module m {
use 0x42::a as aliased_a;
friend 0x42::A;
friend aliased_a; // ERROR!
// ^^^^^^^^ Duplicate friend declaration '0x42::a'. Friend declarations in a module must be unique
}
}