Rust通过包和模块来组织所有的代码,其中每一个Rust项目都是一个包。平时所说的实现给中功能的第三方库每一个都是一个包,这些库都是以一个包的形式发布。

一个Rust项目可以依赖其他的包,这只需要在 Cargo.toml[dependencies] 中列出即可。所有在 Cargo.toml 中列出的被依赖包,都可以需要使用它们的代码文件中使用 extern crate 声明使用。

例如有以下依赖:

  1. [dependencies]
  2. # 这里没有书写任何被依赖库的版本,*代表使用最新版本
  3. image = "*"

那么在 main.rs 文件的开头就需要这样来引用。

  1. extern crate image;

模块

模块是Rust中代码的命名空间,是函数、类型、结构体等代码的容器。包解决的是Rust项目间代码共享的问题,而模块解决的是项目内部代码组织的问题。模块可以嵌套,一个模块拥有一系列的子模块是非常常见的。

如果把所有的模块都书写在一个文件中,那么可以采用以下形式。

  1. mod master_module {
  2. pub mod sub_module_1 {
  3. // 这个子模块是公共的,可以被其他的模块访问到
  4. ...
  5. }
  6. mod sub_module_2 {
  7. // 这个子模块是私有的,从其他的模块是无法访问到的
  8. ...
  9. }
  10. }

模块中的内容默认都是私有的,只有添加了 pub 关键字以后,才会变为公共的,可以被外部访问到。

如果需要把模块定义在独立的文件或者文件夹中,那么就需要使用模块的声明语法了。假设有以下项目结构。
rust项目目录图.svg
在这个项目中, direct.rs 是一个存在于独立文件的模块,目录 composite 是一个存在与独立文件夹的模块,所以这两个模块都需要在 main.rs 中声明。在 main.rs 文件的开头就可以如下一样声明。

  1. pub mod direct;
  2. pub mod composite;

这样一来,如果在 main.rs 同目录下,如果存在 direct.rs ,Rust就会把 direct.rs 作为一个模块来对待,并且在 direct.rs 文件中不必再使用 mod 关键字声明模块了。对于目录 composite ,Rust会首先去寻找其中的 mod.rs 文件,这个文件是使用目录作为模块的统领文件,其下的所有子模块也都是在这个 mod.rs 文件中定义。

模块 composite 下的子模块需要在 mod.rs 文件中定义,其中内容如以下示例所示。

  1. pub mod analysis;
  2. pub mod statistics;

mod.rs 文件中除了可以包含子模块的定义以外,要包含的还有当前模块中需要定义的功能内容。

内容导入

在任何时候,都可以使用操作符 :: 采用绝对路径的方式访问模块中的内容,例如从 main.rs 访问 analysis.rs 中定义的内容就如同下面这样。

  1. ::composite::analysis::AnalysisDefinedContent

这些书写较为繁琐,所以可以提前使用 use 关键字将要使用的内容导入。导入会让被导入的内容成为当前模块中的一个局部别名。 use 关键字会自动转换根路径,所以不需要使用最前导的 :: 操作符。例如导入上例的内容,格式就如下所示。

  1. use composite::analysis::AnalysisDefinedContent;
  2. // 还可以一次性导入多个内容
  3. use composite::analysis::{AnalysisDefinedContent, AnotherUseableContent};
  4. // 或者直接导入全部内容
  5. use composite::analysis::*;
  6. // 导入一个模块
  7. use composite::analysis;

使用 use 导入模块中的内容不仅可以导入具体内容,还可以导入一个模块,这样模块中可访问的内容就可以使用 module::content 的格式来访问了。

模块不会从其父模块继承名字,子模块也看不到父模块中定义的内容,即便这些内容都是公共的。如果要在子模块中使用父模块中定义的内容,需要使用以下声明明确导入父模块声明的内容。

  1. use super::ParentDefinedContent;

然而父模块要访问子模块中定义的内容,也同样需要明确导入。

  1. use self::ChildModule::ChildDefinedContent;