模块

modules.md
commit: eabdf09207bf3563ae96db9d576de0758c413d5d
本章译文最后维护日期:2021-1-24

句法:
Module :
      unsafe? mod IDENTIFIER ;
   | unsafe? mod IDENTIFIER {
        InnerAttribute*
        Item*
      }

模块是零个或多个程序项的容器。

模块项是一个用花括号括起来的,有名称的,并以关键字 mod 作为前缀的模块。模块项将一个新的具名模块引入到组成 crate 的模块树中。模块可以任意嵌套。

模块的一个例子:

#![allow(unused)]
fn main() {
mod math {
    type Complex = (f64, f64);
    fn sin(f: f64) -> f64 {
        /* ... */
      unimplemented!();
    }
    fn cos(f: f64) -> f64 {
        /* ... */
      unimplemented!();
    }
    fn tan(f: f64) -> f64 {
        /* ... */
      unimplemented!();
    }
}
}

模块和类型共享相同的命名空间。禁止在同一个作用域中声明与此作用域下模块同名的具名类型(named type):也就是说,类型定义、trait、结构体、枚举、联合体、类型参数或 crate 不能在其作用域中屏蔽此作用域中也生效的模块名称,反之亦然。使用 use 引入到当前作用域的程序项也受这个限制。

在句法上,关键字 unsafe 允许出现在关键字 mod 之前,但是在语义层面却会被弃用。这种设计允许宏在将关键字 unsafe 从 token流中移除之前利用此句法来使用此关键字。

Module Source Filenames

模块的源文件名

没有代码体的模块是从外部文件加载的。当模块没有 path 属性限制时,文件的路径和逻辑上的模块路径互为镜像。祖先模块的路径组件(path component)是此模块文件的目录,而模块的内容存在一个以该模块名为文件名,以 .rs 为扩展文件名的文件中。例如,下面的示例可以反映这种模块结构和文件系统结构相互映射的关系:

模块路径文件系统路径文件内容
cratelib.rsmod util;
crate::utilutil.rsmod config;
crate::util::configutil/config.rs

当一个目录下有一个名为 mod.rs 的源文件时,模块的文件名也可以和这个目录互相映射。上面的例子也可以用一个承载同一源码内容的名为 util/mod.rs 的实体文件来表达模块路径 crate::util。注意不允许 util.rsutil/mod.rs 同时存在。

注意:在rustc 1.30 版本之前,使用文件 mod.rs 是加载嵌套子模块的方法。现在鼓励使用新的命名约定,因为它更一致,并且可以避免在项目中搞出许多名为 mod.rs 的文件。

The path attribute

path属性

用于加载外部文件模块的目录和文件可以受 path属性的影响。(或者说可以联合使用 path属性来重新指定那种没有代码体的模块声明的加载对象的文件路径。)

对于不在内联模块(inline module)块内的模块上的 path属性,此属性引入的文件的路径为相对于当前源文件所在的目录。例如,下面的代码片段将使用基于其所在位置的路径:

#[path = "foo.rs"]
mod c;
Source Filec's File Locationc's Module Path
src/a/b.rssrc/a/foo.rscrate::a::b::c
src/a/mod.rssrc/a/foo.rscrate::a::c

对于处在内联模块块内的 path属性,此属性引入的文件的路径取决于 path属性所在的源文件的类型。(先对源文件进行分类,)“mod-rs”源文件是根模块(比如是 lib.rsmain.rs)和文件名为 mod.rs 的模块,“非mod-rs”源文件是所有其他模块文件。(那)在 mod-rs 文件中,内联模块块内的 path 属性(引入的文件的)路径是相对于 mod-rs 文件的目录(该目录包括作为目录的内联模块组件名)。对于非mod-rs 文件,除了路径以此模块名为目录前段外,其他是一样的。例如,下面的代码片段将使用基于其所在位置的路径:

mod inline {
    #[path = "other.rs"]
    mod inner;
}
Source Fileinner's File Locationinner's Module Path
src/a/b.rssrc/a/b/inline/other.rscrate::a::b::inline::inner
src/a/mod.rssrc/a/inline/other.rscrate::a::inline::inner

在内联模块和其内嵌模块上混合应用上述 path属性规则的一个例子(mod-rs 和非mod-rs 文件都适用):

#[path = "thread_files"]
mod thread { // 译者注:有模块要内联进来的内联模块
    // 从相对于当前源文件的目录下的 `thread_files/tls.rs` 文件里载 `local_data` 模块。
    #[path = "tls.rs"]
    mod local_data; // 译者注:内嵌模块
}

Attributes on Modules

模块上的属性

模块和所有程序项一样能接受外部属性。它们也能接受内部属性:可以在带有代码体的模块的 { 之后,也可以在模块源文件的开头(但须在可选的 BOM 和 shebang 之后)。

在模块中有意义的内置属性是 cfgdeprecateddoclint检查类属性pathno_implicit_prelude。模块也能接受宏属性。