昨天我们学完了第六章相关知识点match
今天我们开启第七章之旅
packages、crates and modules
现在我们在小打小闹,最多就一俩个fn
和struct
。
而一个最小的项目都可能有好几十个fn
或者其他,并且随着后续开发,体量会继续增大。
这个时候如果我们的代码都堆在一起就会非常恶心和难管理。
这就需要用到今天学的知识了,大概是以下这五点。
packages
和crates
crate
有箱的意思,但是中文说的怪怪的。。。。所以这里都叫crate
了。
crates
我们之前的文章里也有简单的说过,这里再加深下印象。
crate
是rust
编译器一次处理的最小的单位。我们知道rust
的编译器是rustc
,而我们操作rustc
编译的时候只能是传入文件名,再往下就不能了。所以得出结论,一个文件既是一个crate
。
而在这个文件中可能包含着很多的module
模块,所以一个crate
就是一个·module tree
,包含多个module
。
crate
有两种类型:
library crate
,也就是一个库crate
,默认入口是lib.rs
文件, 他们不能被编译成可执行文件,也没有main
函数。与之相反,他们会被当做功能性的库,可被其他项目引入,比如我们之前用过的Rand
的库,大多数时候,当说一个crate
的时候都是指的库crate
。binary crate
,二进制crate
,他们编译后会变成可执行的文件,也就是.exe
文件(window
系统)。有个点需要注意,那就是默认是main.rs
文件的main
函数作为入口,不需要配置。而包packages
相信大家都知道是啥了,这里简单说一下。
多个crate
组合到一起,但不只是这样。它包含一个Cargo.toml
的配置文件,用于配置项目。
有个点需要注意,那就是一个packages
并不等价于一个project
。它可以包含多个project
,这些project
共用同一个Cargo.toml
文件。
一个packages
至少拥有一个crate
,可以包含多个binary crate
, 但是只允许有一个library crate
。
modules
模块这玩意儿大家应该都很熟了,不过前端的开发应该对模块声明没有什么概念,因为工程化之后一个文件就是一个模块,如果你看过打包后的文件,其实一个立即执行函数,这就是一个模块。
扯远了,在rust
中定义一个模块需要用到关键字mod
,来看下例子
我们声明了一个module
:animal
。然后又在里面声明了dog、cat、fish
三个mod
。
module
是允许嵌套的,module
的名字规范是小写字母 + 下划线。
一个crate
中可以允许有多个mod
,一个module
里也允许有多个module
。
module
里的东西默认是私有的(private
),如果想要访问的话,需要开启public
.
不过在这之前,我们要知道怎么使用module
里的东西,我们来改下我们的module
,给它加个函数方便我们调用。
我们在dog
这个module
里声明了一个eat
的method
。
可以看到访问module
里的东西需要用::
符号。
然后由于module
默认私有,所以这里自然就会报错
然后我们可以通过pub
关键字让module
变成public
这个时候就没报错了
在遇到这个animal
的module
时,编译器会去找这个module
的位置,首先会在当前文件里找,找不到会去到src/animal.rs
,找不到又会找src/animal/mod.rs
文件。
而遇到dog
这个module
的时候则会这么找:
src/animal/dog.rs
src/animal/dog/mod.rs
另外有个点我们需要注意,那就是module
里的东西是不能访问外部的东西的
这个点和作用域里的不同,那么要怎么用module
外的东西呢?下面会说到。
path
访问module
上面已经简单地说到了,访问一个module
里的东西需要::
符号,而且默认是私有的。
我们来加深下印象。
其实访问一个crate
有两种方式:
crate
,比如crate::animal::dog
表示从根crate
开始找,还记得我们上面说的吗?crate
是由多个module
组成,是module tree
,所以你直接从crate
开始找就表示从根root
开始找。animal::dog::eat
就是一个相对路径,表示当前文件中的animal
这个module
里的dog
这个module
里的eat
方法。所以上面那个找不到路径的报错我们可以使用绝对路径来访问
由于这个test
方法是在文件最顶层的,所以用常规相对路径拿不到。
但如果我们还想用相对路径呢?官方提供了一个关键词super
[4]
如果一个module
能确定不会发生相对移动,那么用相对路径会是一个不错的选择。但是大多数情况下我们都是用绝对路径,因为这样会更安全。
现在我们都是在同一个文件中测试,但实际开发肯定是得跨文件的,所以我们来把module
放到其他文件中。
官方推荐了一种项目规范[6] ,一般创建项目的时候src
下默认会有一个main.rs
,这个前面说过了是binary crate
的入口,这个时候我们还需要在src
文件夹下创建一个lib.rs
文件。为什么要这么做呢?我们把通用(非业务)的代码都放到这个lib.rs
文件中,而前面说过这个lib.rs
是作为library crate
的入口,会被编译成一个库,这个库到时候就能被其他项目使用。
真是一举俩得~ 双赢。
话不多说,我们在src
下创建个lib.rs
文件,然后我们再创建一个animal
的文件,用来存放animal
这个module
,不过我们不需要把animal
这个名字也移动过去,因为crate
默认是当前文件名字,如果再把animal
移动过去则别的地方要这样写animal::animal
。
ok
这样就拆分完了,接下来我们要在别的文件中引用这个animal crate
use
来引入模块我们可以通过use
关键字,直接引入模块里的东西,这样即保证了绝对路径的安全,又不用写那么长了。
先来看下同文件中怎么使用。
use crate::animal::dog
,这样就能直接用dog::eat
而不用crate::animal::dog::eat
这样了。
当然,这个mod
必须是pub
的。
而我们现在拆分成多个文件了,那么我们来试下从别的文件里引入。
main.rs
文件中
mod animal
表示引入了animal
这个module
, 这样就能用这个animal.rs
文件中的所有pub
的mod
了。
你也可以不用use
关键字,直接animal::dog::eat
也是可以的。
另外如果你不引入这个mod
,你可以通过全局的路径引入,比如
concept
是我们的package
名字。
另外有一点,那就是一般我们想要放入lib
中的crate
都会抽一个专门的文件,比如这个animal
,然后再引入lib.rs
中,并且pub
出去。比如:
有些module
中的方法或者struct
等的名字会重复,但由于module
不同使得他们可以共存,这种时候我们就得确保上级路径也写了,但这样就未免会有些麻烦。
所幸rust
提供了as
关键字允许local name
,就像js
中的一样,可以重写名字。来看下例子
这个时候as
就很有用了。
这样就可以啦。
今天我们把整个第七章都学完了,学了package、crate、module、pub、use、as
等,都是一些概念,比较好懂。
如果觉得对你有帮助的话,请务必点个赞,谢谢~
居家办公就是爽,今天摸了一天鱼~
编辑于 2022-12-10 10:23・IP 属地广东