rust中的模块系统
模块系统
模块系统存在的原因是代码量随着项目的增加而增加。日益庞大的系统就会有日益庞大的代码,这个时候组织项目的代码显得尤为重要。比如前端的工程化就是解决这个问题的,不得不说在当年前端能想到工程化的都是大佬哇。
各种语言的模块化
javascript中的模块化
这个是在javascript中到的导出的语法,在javascript中使用export,或者default export。来实现导入导出(这里不讨论node环境下的语法)
export function show() { console.log("模块化") }
导入语法
import {show} from './show.js'
javascript中的导入语法很简单,直接引入js文件即可,特别方便。
go 语言中的模块化
go语言的导出就是变量或函数名首字母大写即可,并不需要“./”,在当前项目中的子集文件夹就是一个package.只需要import一个package就可以使用这个包下的所有首字母大写的变量或函数了,下面是go语言导入的语法
import "project/packagename" // 项目名称/包名
可见在go和javascript中,他们的导入导出语法都设置得极其简单,上手就能用。
rust中的模块化
rust中的模块化的概念比较多,比较复杂。下面为用rust圣经的这本书里写的copy过来
- 包(Packages):Cargo 的一个功能,它允许你构建、测试和分享 crate。
- Crates :一个模块的树形结构,它形成了库或二进制项目。
- 模块(Modules)和 use:允许你控制作用域和路径的私有性。
- 路径(path):一个命名例如结构体、函数或模块等项的方式。
我的理解
- 包(package):这个包应该就是指一个项目
- Crates: 这个应该就是指模块的树型结构,比如linux里的/,这个crates就是指/
- 模块(Modules):这个就是指使用mod关键字来标识一个模块
- 路径(path):这个路径并不是javascript那样的路径,而是package::crates::mod这样子的路径
开始创建一个模块
首先,得在main.rs中声明模块,如下所示
pub mod say; fn main() { }
添加了这个模块声明后rust的编译器会自动寻找main.rs同级目录下的say文件,当然也可以是文件夹,但是前提是文件夹中必须存在mod.rs, 如下所示
// 这是同级目录下的say文件的用法 studySay ├── Cargo.lock ├── Cargo.toml └── src ├── say │ └── hello.rs ├── say.rs └── main.rs // 这是文件夹的用法 studySay ├── Cargo.lock ├── Cargo.toml └── src ├── say │ └── hello.rs │ └── mod.rs └── main.rs
rust提供了两种方式来声明子模块(当然有第三种方式,但是这里不做讨论。因为第三种方式是内联方式,懂的都懂哈哈哈~o~)
下面是代码的实现
方式一:使用根目录文件
// main.rs pub mod say; // 此处声明了say模块,rust编译器就会查找同级目录下的say.rs文件或者同级下的say文件夹 fn main() {}
// say.rs pub mod hello; // 此处是声明子模块
// say/hello.rs // 创建一个say_hello模块 pub mod say_hello { // 模块里的一个方法 pub fn say_hello_world() { println!("say hello world") } }
方式二: 使用mod.rs文件
// main.rs pub mod say; // 此处声明了say模块,rust编译器就会查找同级目录下的say.rs文件或者同级下的say文件夹 fn main() {}
// say/mod.rs pub mod hello; // 此处是声明子模块
// say/hello.rs // 创建一个say_hello模块 pub mod say_hello { // 模块里的一个方法 pub fn say_hello_world() { println!("say hello world") } }
可以看出上面的两种方式的唯一区别就是在say.rs和say/mod.rs的文件名不一样,至于为什么rust中存在这两种方式应该是考虑到了兼容性问题,这是rust圣经中的原话: "
另一种文件路径
目前为止我们介绍了 Rust 编译器所最常用的文件路径;不过一种更老的文件路径也仍然是支持的。
对于声明于 crate 根的 front_of_house 模块,编译器会在如下位置查找模块代码:
src/front_of_house.rs(我们所介绍的)
src/front_of_house/mod.rs(老风格,不过仍然支持)
对于 front_of_house 的子模块 hosting,编译器会在如下位置查找模块代码:
src/front_of_house/hosting.rs(我们所介绍的)
src/front_of_house/hosting/mod.rs(老风格,不过仍然支持)
如果你对同一模块同时使用这两种路径风格,会得到一个编译错误。在同一项目中的不同模块混用不同的路径风格是允许的,不过这会使他人感到疑惑。
使用 mod.rs 这一文件名的风格的主要缺点是会导致项目中出现很多 mod.rs 文件,当你在编辑器中同时打开它们时会感到疑惑。
",所以按照官方的说明,使用say.rs的这种方式更加现代化。
使用mod
上面说明里如何声明mod,现在我们需要使用mod。 代码如下
// 找到say模块中的hello模块中的say_hello模块 use say::hello::say_hello; // 使用模块 pub mod say; // 声明模块 fn main() { // 使用say_hello模块下的say_hello_world方法 say_hello::say_hello_world(); }
上述就是一直困扰为很久的rust模块的问题,真的和c/cpp那样要一个个模块声明,感觉真的好麻烦啊。