坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.1.3

前言

昨天我们学完了第六章相关知识点match

坏蛋Dan:rust基础学习--day13

今天我们开启第七章之旅


packages、crates and modules

现在我们在小打小闹,最多就一俩个fnstruct

而一个最小的项目都可能有好几十个fn或者其他,并且随着后续开发,体量会继续增大。

这个时候如果我们的代码都堆在一起就会非常恶心和难管理。

这就需要用到今天学的知识了,大概是以下这五点。

  • Packages: A Cargo feature that lets you build, test, and share crates
  • Crates: A tree of modules that produces a library or executable
  • Modules and use: Let you control the organization, scope, and privacy of paths
  • Paths: A way of naming an item, such as a struct, function, or module

packagescrates

crate有箱的意思,但是中文说的怪怪的。。。。所以这里都叫crate了。

crates我们之前的文章里也有简单的说过,这里再加深下印象。

craterust编译器一次处理的最小的单位。我们知道rust的编译器是rustc,而我们操作rustc编译的时候只能是传入文件名,再往下就不能了。所以得出结论,一个文件既是一个crate

而在这个文件中可能包含着很多的module模块,所以一个crate就是一个·module tree,包含多个module

crate有两种类型:

  1. library crate,也就是一个库crate,默认入口是lib.rs文件, 他们不能被编译成可执行文件,也没有main函数。与之相反,他们会被当做功能性的库,可被其他项目引入,比如我们之前用过的Rand的库,大多数时候,当说一个crate的时候都是指的库crate
  2. 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,来看下例子

我们声明了一个moduleanimal。然后又在里面声明了dog、cat、fish三个mod

module是允许嵌套的,module的名字规范是小写字母 + 下划线。

一个crate中可以允许有多个mod,一个module里也允许有多个module

module里的东西默认是私有的(private),如果想要访问的话,需要开启public.

不过在这之前,我们要知道怎么使用module里的东西,我们来改下我们的module,给它加个函数方便我们调用。

我们在dog这个module里声明了一个eatmethod

可以看到访问module里的东西需要用::符号。

然后由于module默认私有,所以这里自然就会报错

然后我们可以通过pub关键字让module变成public

这个时候就没报错了

在遇到这个animalmodule时,编译器会去找这个module的位置,首先会在当前文件里找,找不到会去到src/animal.rs,找不到又会找src/animal/mod.rs文件。

而遇到dog这个module的时候则会这么找:

  1. 到当前文件里找
  2. src/animal/dog.rs
  3. src/animal/dog/mod.rs

另外有个点我们需要注意,那就是module里的东西是不能访问外部的东西的

这个点和作用域里的不同,那么要怎么用module外的东西呢?下面会说到。


path访问module

上面已经简单地说到了,访问一个module里的东西需要::符号,而且默认是私有的。

我们来加深下印象。

其实访问一个crate有两种方式:

  1. 绝对路径,需要用到关键词crate,比如crate::animal::dog表示从根crate开始找,还记得我们上面说的吗?crate是由多个module组成,是module tree,所以你直接从crate开始找就表示从根root开始找。
  2. 相对路径,就是我们的例子写的那样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文件中的所有pubmod了。

你也可以不用use关键字,直接animal::dog::eat也是可以的。

另外如果你不引入这个mod,你可以通过全局的路径引入,比如

concept是我们的package名字。

另外有一点,那就是一般我们想要放入lib中的crate都会抽一个专门的文件,比如这个animal,然后再引入lib.rs中,并且pub出去。比如:


as重命名

有些module中的方法或者struct等的名字会重复,但由于module不同使得他们可以共存,这种时候我们就得确保上级路径也写了,但这样就未免会有些麻烦。

所幸rust提供了as关键字允许local name,就像js中的一样,可以重写名字。来看下例子

这个时候as就很有用了。

这样就可以啦。


总结

今天我们把整个第七章都学完了,学了package、crate、module、pub、use、as等,都是一些概念,比较好懂。

如果觉得对你有帮助的话,请务必点个赞,谢谢~

居家办公就是爽,今天摸了一天鱼~

参考

  1. ^rust-packages-and-crates https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html#packages-and-crates
  2. ^rust-define-module-to-control-scoped-and-private https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html#defining-modules-to-control-scope-and-privacy
  3. ^rust-path-for-refer-to-an-item-in-module-tree https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#paths-for-referring-to-an-item-in-the-module-tree
  4. ^rust-use-super https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#starting-relative-paths-with-super
  5. ^rust-separating-modules-into-different-files https://doc.rust-lang.org/book/ch07-05-separating-modules-into-different-files.html#separating-modules-into-different-files
  6. ^rust-projet-recommand https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#best-practices-for-packages-with-a-binary-and-a-library
  7. ^rust-use https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html

编辑于 2022-12-10 10:23・IP 属地广东