今天我们来看看 Rust 的模块系统。每个 Rust 程序都是起始于一个根模块。如果你创建的是一个库项目,那么根模块就是 lib.rs 文件。如果你创建的是一个可执行程序项目,那你的根模块就是带有 main 函数的那个文件,一般默认为 main.rs。当你的项目变得越来越大时,必然就需要分模块进行管理了。下面我们来看看 Rust 如何创建模块。
内嵌模块
在 Rust 中创建一个模块最简单的办法就是在一个模块内使用 mod{} 代码块(模块中的模块,或者想象成子模块也行)。让我们来看看代码:
mod somefoods { struct Rice; struct Noodle; struct Dumpling;}fn main() { let food = Rice;}
我们在上面的代码中创建了一个内部模块 somefoods。如果我们想在一个文件中创建一个模块,就使用 mod 关键字,然后是模块的名字,然后是大括号。在大括号中我们可以定义任何类型的数据,甚至还是一个模块。在上面代码中,我们在模块中定义了三个结构:Rice,Noodle,Dumpling。然后我们在 main 函数中使用了其中的 Rice 结构,让我们运行程序看看结果:
结果是无法通过编译,编译器告诉我们无法找到 Rice 类型。好吧,那我们按照编译器给我们的提示改造代码如下:
mod somefoods { struct Rice; struct Noodle; struct Dumpling;}use crate::somefoods::Rice;fn main() { let food = Rice;}
我们添加 use 语句导入 Rice 类型。对,确实应该这样,像很多其他语言一样,使用什么要先导入。现在我们运行代码,结果还是报错,如下图所示:
编译器告诉我们 Rice 是私有的。原来使用 mod 定义的模块内部,所有的定义默认都是私有的。如果我们想要使用它们,就需要把它们变成公有可访问的。继续改造代码如下:
mod somefoods { pub struct Rice; struct Noodle; struct Dumpling;}use crate::somefoods::Rice;fn main() { let food = Rice;}
我们在定义 Rice 的语句前面加上了 pub 关键字,表明这个定义是公有可访问的。现在我们再运行程序,发现终于通过了。
文件模块
我们知道 main.rs 或者 lib.rs 为初始项目的根模块,这里面的引申含义就是文件就是一个模块。假设我们创建了一个可执行程序项目,然后在和 main.rs 文件同级的目录下创建一个文件 file_module.rs。文件的内容如下:
pub struct Hello;impl Hello { pub fn init() { println!("hello"); }}
就是一个简单的结构,并为这个结构定义了一个静态方法 init,这个方法会打印 hello 字样。如果我们想要在 main.rs 中使用这个模块,在 main.rs 中这样写:
mod file_module;use crate::file_module::Hello;fn main() { Hello::init();}
还是使用 mod 关键字声明使用哪个模块,也就是 file_module.rs。然后使用 use 导入这个模块中你要使用的数据类型。有的同学可能会对 use 语句中的 crate 有所疑问,不知道这从何而来,下面来讲一下。crate 还可以换为 self 和 super。它们代表着模块的寻找方式。
crate:从根模块开始找起。
self:从当前模块找起。也就是你使用 use 的这个文件。
super:从父模块找起。比如上例子模块 somefoods,如果要引用 main.rs 中的数据,就可以使用 super。
目录模块
我们还可以创建一个目录作为模块。首先我们创建一个 abc 目录。在 abc 目录或者叫模块中创建一个文件子模块 def.rs。def.rs 中定义了个结构,代码如下:
pub struct Def;impl Def { pub fn init() { println!("this is def"); }}
如果我们想在 main.rs 中使用 Def 这个结构,该如何导入呢?我们要在 abc 目录下创建 mod.rs。代码如下:
mod def;pub use self::def::Def;pub fn from_abc() { println!("abc");}
首先使用 mod 关键字声明 def 模块,然后 pub use 导入导出 Def 结构。一般这种情况下使用 self 找包。同时 abc 模块自己有个导出函数。下面看看在 main.rs 中如何使用:
mod abc;use abc::Def;fn main() { abc::from_abc(); Def::init();}
同样用 mod 声明模块 abc,然后导入 abc 模块下的数据,注意这里没有 abc 的子模块导入,因为在 abc 的模块文件中已经导出了。
以上就是 Rust 中使用模块组织代码的方式。如有任何问题,请添加微信公众号“读一读我”。