友元模块
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
只能在模块作用域中声明,而不能在表达式块作用域中声明.
友元声明可以出现在任何允许顶层构造(如 use
,function
,struct
等)的位置.
但为了可读性,建议将友元声明放在模块定义的开始部分.
注意友元的概念不适用于 Move 脚本:
- Move 脚本不能声明
friend
模块,因为这样做没有意义:脚本中定义的函数没有调用机制 - Move 模块也不能声明
friend
脚本,因为脚本是临时代码片段,永远不会发布到全局存储中
友元声明规则
Section titled “友元声明规则”友元声明需遵循以下规则:
-
模块不能将自己声明为友元:
module 0x42::m {friend Self; // 错误!// ^^^^ 不能将模块自身声明为友元}module 0x43::m {friend 0x43::M; // 错误// ^^^^^^^ 不能将模块自身声明为友元} -
友元模块必须能被编译器识别:
module 0x42::m {friend 0x42::nonexistent; // 错误!// ^^^^^^^^^^^^^^^^^ 未绑定模块 '0x42::nonexistent'} -
友元模块必须位于同一账户地址下(注意:这不是技术限制,而是当前策略要求,未来_可能_会放宽):
module 0x42::m {}module 0x43::n {friend 0x42::m; // 错误!// ^^^^^^^ 不能将当前地址外的模块声明为友元} -
友元关系不能形成循环依赖:
不允许在友元关系中出现循环,例如
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; // 错误!// ^^^^^^ 这个友元关系会创建循环依赖:'0x2::b' 是 '0x2::a' 的友元,后者使用了 '0x2::c',而 '0x2::c' 又是 '0x2::b' 的友元}module c {public fun c() {}}} -
模块的友元列表不能包含重复项.
address 0x42 {module a {}```模块 m {使用 0x42::a 作为 aliased_a;友元 0x42::A;友元 aliased_a; // 错误!// ^^^^^^^^^ 重复的友元声明 '0x42::a'。模块中的友元声明必须是唯一的}}