Rust Mod和文件系统
文章目录
本文是读《Rust程序设计语言第二版》Mod和文件系统相关内容的笔记。阅读这本书所敲的代码放在Github上。代码没有按书的结构分章节创建工程,而是将所有代码放在一个单独的工程中。
模块
使用Cargo创建新项目时,默认创建的是二进制crate而不是创建库crate。创建库crate要使用--lib参数而不是--bin参数:
|
|
这时会生成src/lib.rs而不是src/main.rs。
在上面链接的示例中,我没有使用这种方式创建mod。因为敲的所有示例都在一个工程中,所以只需要添加lib.rs,Cargo.toml中也没有增加内容,只是添加了调用lib.rs的uselib.rs。
模块定义
Rust默认只知道lib.rs中的内容,通过它来查找对应的模块名.rs。
可以在src/lib.rs中定义一个或多个模块
|
|
在模块外调用这些函数,需要指定模块名并使用命名空间语法::,如:network::connect()。
模块间是可以嵌套的:
|
|
模块移动到其它文件
位于层级中的模块,非常类似于文件系统结构。可以利用Rust模块系统,使用多个文件分解Rust项目。这样就不需要将所有代码都放在src/lib.rs或src/main.rs了。
下面我们将要把下面的client、network和server三个模块拆分至各自的.rs文件中。
src/lib.rs
|
|
第一步:拆分client
src/lib.rs
|
|
src/client.rs
|
|
注意在上面的client.rs里,不再需要mod声明,因为在src/lib.rs中已经声明了client mod。
第二步:拆分network
src/lib.rs
|
|
src/network.rs
|
|
这个拆分方法与上次一样,只不过在network.rs中,保留了server模块的声明。
第三步:拆分server
如果我们按上面的方式继续拆。就是将src/network.rs改为
|
|
并增加src/server.rs
|
|
但是,在这样修改后cargo build会报错。
|
|
这说明src/network.rs与src/lib.rs在某些方面是不同的。错误信息中建议的方式是:
-
新建名为
network的目录,这是父模块的名字。 -
将
src/network.rs移至新建的network目录,并重命名为src/network/mod.rs。 -
将
src/server.rs移动到network目录中。
整个目录结构变为:
|
|
移动完毕后,各文件的内容如下:
src/lib.rs
|
|
src/client.rs
|
|
src/network/mod.rs
|
|
src/network/server.rs
|
|
使用src/usrlib.rs调用这些模块:
|
|
模块文件系统的规则
-
如果
foo模块没有子模块,应该foo的声明放在foo.rs文件中。 -
如果
foo模块有子模块,应该将foo的声明放在foo/mod.rs中。
使用pub控制可见性
使用extern crate communicator可以从外部模块中将communicator库crate引入到作用域。从外部crate的角度来看,我们所创建的所有模块都位于一个与crate同名的模块内,即位于communicator内部。这个顶层模块被称为crate的根模块。
即便在项目的子模块中使用外部crate,extern crate也应该位于根模块(即src/main.rs或src/lib.rs中)。在子模块中,我们可以像顶层模块那样引用外部crate中的项了。
Rust上下文中涉及公有和私有的概念。所有代码默认是私有的,除了自己之外,别人不允许使用这些代码。如果不在自己的项目中使用某个函数,编译器会警告该函数未被使用。
为了将函数标记为公有,需要在声明的开头增加pub关键字。
私有性规则
-
如果一个项是公有的,它能被任何父模块访问
-
如果一个项是私有的,它能被其直接父模块及任何子模块访问
在不同模块中引用命名
使用use关键字将指定的模块引入作用域;它并不会将其子模块也引入。
枚举也像模块一样组成了某种命名空间,也可以使用use来导入枚举成员。
可以使用*语法,也称glob运算符将某个命名空间下的所有名称都引入作用域:use TrafficLight::*;
使用super关键字访问父模块:super::client::connect();
文章作者 Jamsa
上次更新 2018-08-21