Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit an issue.

友元模块

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::B0x42::C 都被视为 0x42::A 的友元:

module 0x42::a {
    friend 0x42::b;
    friend 0x42::c;
}

use 语句不同,friend 只能在模块作用域中声明,而不能在表达式块作用域中声明。 友元声明可以出现在任何允许顶层构造(如 usefunctionstruct 等)的位置。 但为了可读性,建议将友元声明放在模块定义的开始部分。

注意友元的概念不适用于 Move 脚本:

  • Move 脚本不能声明 friend 模块,因为这样做没有意义:脚本中定义的函数没有调用机制
  • Move 模块也不能声明 friend 脚本,因为脚本是临时代码片段,永远不会发布到全局存储中

友元声明规则

友元声明需遵循以下规则:

  • 模块不能将自己声明为友元:

    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'。模块中的友元声明必须是唯一的
        }
      }