模块是rust的命名空间,它包含函数,类型,常量等项。它用于项目内部使用,而包则用于项目之间的代码共享。
模块是项的集合,如果项前面有pub关键字,那么它可以在被模块外部的代码访问,没有指定pub关键字的项都是私有的。模块可以嵌套,一个模块包含多个子模块的情况相当普遍。
模块可以写成mod spores;不包含模块体,这样rust会在同级目录查找spores.rs文件当成模块体,spores.rs文件里面不用再声明它是个模块。这种模块和直接在同一个文件里写模块声明和模块体唯一的区别就是代码位置不同,关于公有和私有的规则还是完全一样。并且rust永远不会分开编译一个模块,即使代码在不同的文件。当rust看到mod spores;的时候它不仅查找spores.rs文件,还查找spores/mod.rs文件,两个文件都不存在和都存在都会报错。
::操作符用于访问模块特征,在项目的任何地方都可以用::std绝对路径的形式访问标准库。以::开头的项路径是绝对路径。使用绝对路径访问标准库的项太冗长,可以先把它导入到当前模块,比如use std::mem;use声明让mem变成一个局部的别名,use声明里的路径都自动转成绝对路径,所以开始的::可以省略。我们可以用use std::mem::swap直接导入swap函数而不是mem模块,但是导入模块更符合编程规范,导入类型,特征和模块,然后用相对路径访问模块里的函数,常量等项。
多个名字可以一起导入,比如use std::collections::{HashMap,HashSet};还可以用\*通配符,比如use std::io::prelude::\*;这仅仅是导入模块里每个项的简写而已。
模块不会自动继承父模块里的项。可以用use supper::项名;来显式导入。super表示父模块,类似的self表示当前模块。use导入模块默认是绝对路径的,你可以用self和super来访问相对路径的项。子模块可以访问父模块里的私有项,但是必须按名字明确地导入。用通配符use super::\*;仅仅导入公有的项。
self和super类似目录结构里的.和..,extern crate把其他项目的根模块引入到项目里,像挂载文件系统一样。
标准库std被自动地链接到每一个项目,就像你的lib.rs或者main.rs包含了一个声明extern crate std;一样。此外一些常用的名字,比如Vec和Result被包含到一个标准的prelude里面会自动导入。就像每个模块都有如下导入use std::prelude::v1::\*;一样。标准的prelude包含一些常用的特征和类型,它并不包含std。因此如果你的项目要用std,需要显式导入,如use std;
结构体的私有属性在结构体声明的模块是可以访问的,在声明的模块外部,只有公有属性可以访问。
用模块来控制访问权限而不是像c++和java那样用类来控制访问权限被证明是好的设计。它消除了getter和setter样板代码,并且消除了c++里的友元。一个模块可以定义多个相互配合的类型,比如frond::LeafMap和frond::LeafMapIter,访问对方的私有属性是需要的,但是对模块外部仍然隐藏了实现细节。
一个impl块不能用pub关键字来修饰,而是应该对impl块里面的方法用pub关键字来修饰。结构体的私有方法和私有属性一样,在结构体声明的模块内部也是可以访问的。
const关键字产生一个常量,语法类似let,除了它可以用pub关键字来修饰,并且类型是必须的。按照编程习惯,用大写单词加下划线来命名常量。static关键字产生一个静态变量。
常量类似c++的#define,它的值被编译到每一个使用的地方。静态变量在程序启动前初始化,并持续到程序结束。使用数字类型和字符串的时候多用常量;生成大量数据或者需要借用引用的时候用静态变量。没有mut的常量,静态变量可以是mut的。rust没有方法确保mut静态变量的独占访问,它是线程不安全的,因此要访问mut静态变量必须在unsafe块里访问。
use和extern crate也是模块的项,尽管它们只是别名,但是也可以是公有的,可以用pub关键字修饰,供模块外部使用。标准的prelude就是一系列pub导入。
extern块也是模块的项,它声明了用其它语言写的一些函数的集合。
rust对声明了却不使用的项会报警告。
