您的位置:首页 > 文旅 > 美景 > 武汉今日头条最新消息_响应式网页设计例子_建设网站需要多少钱_长春网站建设解决方案

武汉今日头条最新消息_响应式网页设计例子_建设网站需要多少钱_长春网站建设解决方案

2025/3/20 11:58:08 来源:https://blog.csdn.net/qq_36393978/article/details/146339937  浏览:    关键词:武汉今日头条最新消息_响应式网页设计例子_建设网站需要多少钱_长春网站建设解决方案
武汉今日头条最新消息_响应式网页设计例子_建设网站需要多少钱_长春网站建设解决方案

文章目录

  • 1. 前言
  • 2. 包和 Crate
  • 3. 定义模块以及模块之间的关系
  • 4. 作用域问题
    • 4.1. 作用域问题初现
    • 4.2. 解决问题一
    • 4.3. 解决问题二
    • 4.4. super 关键字
    • 4.5. 将路径引入作用域
    • 4.6. as 关键字
    • 4.7. pub use 重导出
  • 5. 引入的问题
    • 5.1. 引入一个外部包
    • 5.2. 嵌套路径来消除大量的 use 行
    • 5.3. 通过 glob 运算符将所有的公有定义引入作用域
  • 6. 将模块拆分为多文件
  • 7. 小结

1. 前言

经过上一小节无聊又有趣的洗礼相信大家已经提起精神进入下一个内容的学习啦~~

这小节将会了解 Rust 中是以什么样的形式和工具来组织和管理自己的代码。我们都知道当代码量和源文件数量达到一定程度时候,井然有序的组织将变得尤为重要,不然我们的代码在外人眼里看来就是一坨*,不仅其他人难以阅读,作为开发者的你回头看去也是一头雾水,悔恨自己写的这是个什么玩意儿。

Rust 中有着严格的作用域限制,有这样的一个模块系统(the model system)来管理作用域,其中包括:

  • Packages):Cargo 的一个功能,它允许你构建、测试和分享 crate
  • Crates :一个模块的树形结构,它形成了库或二进制项目;
  • 模块Modules)和 use:允许你控制作用域和路径的私有性;
  • 路径path):一个命名例如结构体、函数或模块等项的方式。

2. 包和 Crate

crateRust 在编译时最小的代码单位。如果你用 rustc 而不是 cargo 来编译一个文件,编译器还是会将那个文件认作一个 cratecrate 可以包含模块,模块可以定义在其他文件,然后和 crate 一起编译。

crate 有两种形式:二进制项。二进制项可以被编译为可执行程序,比如一个命令行程序或者一个 web server。它们必须有一个 main 函数来定义当程序被执行的时候所需要做的事情。目前我们所创建的 crate 都是二进制项。

并没有 main 函数,它们也不会编译为可执行程序,库可以提供一些函数或结构体之类的,就如之前我们所使用过的 rand 库就为我们提供了随机数函数。

包(package)是提供一系列功能的一个或者多个 crate。一个包会包含一个 Cargo.toml 文件,阐述如何去构建这些 crateCargo 就是一个包含构建你代码的二进制项的包。Cargo 也包含这些二进制项所依赖的库。其他项目也能用 Cargo 库来实现与 Cargo 命令行程序一样的逻辑。

包中可以包含至多一个库 crate(library crate)。包中可以包含任意多个二进制 crate(binary crate),但是必须至少包含一个 crate(无论是库的还是二进制的)。

让我们来看看创建包的时候会发生什么。首先,我们输入命令 cargo new my-project

$ cargo new my-projectCreated binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

Cargo 给我们创建了什么,Cargo 会给我们的包创建一个 Cargo.toml 文件。查看 Cargo.toml 的内容,会发现并没有提到 src/main.rs,因为 Cargo 默认 src/main.rs 就是一个与包同名的二进制 cratecrate 根。

同样执行 cargo new --lib my-library 会有同样的目录结构生成,不同的是这里的 src/main.rs 变成了 src/lib.rs,并且 src/lib.rs 就是 crate 根。crate 根文件将由 Cargo 传递给 rustc 来实际构建库或者二进制项目。

这里只是包含一个 src/main.rs 的包,意味着它只含有一个名为 my-project 的二进制 crate。如果一个包同时含有 src/main.rssrc/lib.rs,则它有两个 crate:一个二进制的和一个库的,且名字都与包相同。通过将文件放在 src/bin 目录下,一个包可以拥有多个二进制 crate:每个 src/bin 下的文件都会被编译成一个独立的二进制 crate

做个简单的实验,首先执行 cargo new multiple_bin

$ cargo new multiple_bin
Creating binary (application) `multiple_bin` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
$ cd multiple_bin
$ tree
.
├── Cargo.lock
├── Cargo.toml
└── src└── main.rs

进入 src,创建 bin 目录,并在其中创建多个 .rs 文件:

$ cd src
$ mkdir bin
$ cp ../main.rs bin01.rs
$ cp ../main.rs bin02.rs
$ cd ../../

编译该项目:

$ cargo buildCompiling multiple_bin v0.1.0 (/home/im01/Miracle/rust/multiple_bin)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── bin
│   │   ├── bin01.rs
│   │   └── bin02.rs
│   └── main.rs
└── target├── CACHEDIR.TAG└── debug├── bin01├── bin01.d├── bin02├── bin02.d├── build├── deps│   ├── bin01-54a8a90b566c47ce│   ├── bin01-54a8a90b566c47ce.d│   ├── bin02-057c31f4258a913d│   ├── bin02-057c31f4258a913d.d│   ├── multiple_bin-79155e437d2fa379│   └── multiple_bin-79155e437d2fa379.d├── examples├── incremental......├── multiple_bin└── multiple_bin.d15 directories, 48 files

[注]:这里为了简洁仅展示了部分主要内容。

target 目录可以看出这里不仅会为 main.rs 生成了与根同名的 multiple_bin 二进制的 crate,还会为在 bin 目录下的两个文件生成对应文件名的二进制 crate

3. 定义模块以及模块之间的关系

这里将会涉及到几个重要的关键字:

  • use:将路径引入作用域;
  • pub:使对应项变为公有性质;
  • as:为同名函数起别名。

在此之前先对几个概念做以解释:

  • rust 项目是从 crate 根节点开始检索代码:这很好理解,对于一个二进制 crate 的根就是 src/main.rs,而库则是 src/lib.rs,就类似在 C/C++ 中总是以 main 函数开始;
  • 声明模块:在 crate 根文件中用 mod 关键字可以声明一个模块,如:
	mod xiaomi_car;	// 中国最大的保时捷&法拉利元素融合高性能新能源汽车集团

这便是声明了一个 xiaomi_car 模块,而当 mod xiaomi_car 后是一个大括号时,这样的方式成为内联,如:

	mod xiaomi_car{fn sale() {}	// 销售部销售小米汽车,金牌销售员:雷将军}
  • 声明子模块:在不是 main.rs 中定义的模块被称为子模块;
  • 公有和私有:一个模块里的代码默认对其夫模块私有。为一个模块加上 pub 关键字即使用 pub mod 来声明模块,则表示将该模块公有化;

看完这些名词解释相信大家在大脑中还是一团浆糊,那么接下来将通过一点小实验逐步让我们梳理清楚现在正在学习的到底是什么。

当下火出天际的汽车行业的雷小军的保时米为例来介绍,保时米集团有这样的部门专门用来营销宣传以及销售汽车被称为销售部Sales Department),还有专门用来生产制造的制造部Manufacturing Department)。

好了,现在让我们来创建一个小米汽车的库,起名为 xiaomi_car

$ cargo new --lib xiaomi_carCreating library `xiaomi_car` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

编辑 src/lib.rs 文件添加如下内容:

mod sales_department {// 车辆售前服务mod pre_sales_service {// 车型咨询fn model_consultation() {}// 制定购车方案fn purchase_plan_options() {}}// 车辆售后服务mod after_sales_service {// 车辆保养服务fn vehicle_maintenance_services() {}// 维修服务fn repair_services() {}}
}

这里我们用关键字 mod 定义了一个名为 sales_department 的模块,接着花括号内为该模块的主体部分。在模块内仍然可以指定其它模块,正如这里的 pre_sales_serviceafter_sales_service 模块是属于 sales_department 的子模块,相应的 sales_department 是他们的父模块。而模块内还可以定义一些其它的各种类型,如结构体、枚举、常量、函数等。

通过以模块的方式将相关的代码定义再一起,这样会更有组织性的管理程序,以 src/main.rssrc/lib.rs 作为 crate 根,构成了一整个模块树module tree)。

上面的代码就展示如下这样结构的设备树。

crate└── sales_department ├── pre_sales_service │   ├── model_consultation│   └── purchase_plan_options└── after_sales_service ├── vehicle_maintenance_services└── repair_services

rust 里仍然是借用家庭关系来描述模块之间的关系,在同一个模块中定义的子模块互为兄弟模块(siblings module),而包含着子模块的模块称为他们的父模块(parent module)。注意,整个模块树都植根于名为 crate 的隐式模块下。这样一来我们就可以更加清晰的设计和组织我们的代码。

4. 作用域问题

4.1. 作用域问题初现

上面我们了解到模块之间的结构可以被抽象成为树状结构,那么不同层之间的模块是否能够相互调用呢?(既然已经这么问了,那么一定是不可以咯~)总而言是,先试试看吧。

// 保时米的销售部门
mod sales_department {// 车辆售前服务mod pre_sales_service {// 车型咨询fn model_consultation() {}// 制定购车方案fn purchase_plan_options() {}// 添加到生产订单fn add_to_production_order() {}}// 车辆售后服务mod after_sales_service {// 车辆保养服务fn vehicle_maintenance_services() {}// 维修服务fn repair_services() {}}
}// 保时米的生产制造部门
mod manufacturing_department {// 生产计划mod production_planning {// 制定生产计划fn specify_production_plan() {// 添加到生产订单add_to_production_order();}}// 总装车间mod final_assembly_workshop {}
}

让我们就这样编译看下能不能通过:

im01@Ubuntu:xiaomi_car$ cargo buildCompiling xiaomi_car v0.1.0 (/home/im01/Miracle/rust/xiaomi_car)
error[E0425]: cannot find function `add_to_production_order` in this scope--> src/lib.rs:23:13|
23 |             add_to_production_order();|             ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope|
note: function `crate::sales_department::pre_sales_service::add_to_production_order` exists but is inaccessible--> src/lib.rs:7:9|
7  |         fn add_to_production_order() {}|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not accessibleFor more information about this error, try `rustc --explain E0425`.
error: could not compile `xiaomi_car` (lib) due to 1 previous error

哦~哦吼吼~,不出意外的出意外了,从错误信息中可以看到,没有在当前范围内找到 add_to_production_order 这个函数,再看到下面的提示告诉我们说,有一个同名的函数存在,但是不可以访问。注意一下,这里有两点问题:

  • 第一:我们函数调用的方式不对,因为调用了一个不存在的函数;
  • 第二:即便我们去调用这个存在的函数,同样存在不可访问的问题。

4.2. 解决问题一

根据提示我们可以解决第一个问题,修改上面代码:

mod sales_department {mod pre_sales_service {//-------------snip----------------fn add_to_production_order() {}//-------------snip----------------}
}mod manufacturing_department {mod production_planning {fn specify_production_plan() {//add_to_production_order();// 绝对路径crate::sales_department::pre_sales_service::add_to_production_order();}}mod final_assembly_workshop {}
}pub fn sales_announcement() {// 相对路径sales_department::pre_sales_service::add_to_production_order();
}

[注]:此处为了突出主要内容,省略了部分无关代码。这里为了说明相对路径问题额外添加 sales_announcement 函数。

这里引入两个概念:

  • 绝对路径:crate 开始,即从根开始按照树状结构索引出来的,每一层之间用 :: 隔开;
  • 相对路径: 从当前位置出发,即从同一层的模块位置出发索引,同样每层之间用 :: 隔开。

好了,这里我们编译一下,看看会出现什么问题:

im01@Ubuntu:xiaomi_car$ cargo buildCompiling xiaomi_car v0.1.0 (/home/im01/Miracle/rust/xiaomi_car)
error[E0603]: module `pre_sales_service` is private--> src/lib.rs:25:38|
25 |             crate::sales_department::pre_sales_service::add_to_production_order();|                                      ^^^^^^^^^^^^^^^^^  ----------------------- function `add_to_production_order` is not publicly re-exported|                                      ||                                      private module|
note: the module `pre_sales_service` is defined here--> src/lib.rs:2:5|
2  |     mod pre_sales_service {|     ^^^^^^^^^^^^^^^^^^^^^error[E0603]: module `pre_sales_service` is private--> src/lib.rs:37:23|
37 |     sales_department::pre_sales_service::add_to_production_order();|                       ^^^^^^^^^^^^^^^^^  ----------------------- function `add_to_production_order` is not publicly re-exported|                       ||                       private module|
note: the module `pre_sales_service` is defined here--> src/lib.rs:2:5|
2  |     mod pre_sales_service {|     ^^^^^^^^^^^^^^^^^^^^^For more information about this error, try `rustc --explain E0603`.
error: could not compile `xiaomi_car` (lib) due to 2 previous errors

错误信息中告诉我们 pre_sales_service 是一个私有模块,被 sales_department 模块私有,因此外部无法访问(这里所指的外部是 pre_sales_service 同层之外)。

4.3. 解决问题二

此时的整个模块树看起来是这样的。

crate├── sales_department │   ├── pre_sales_service │   │   ├── model_consultation│   │   ├── purchase_plan_options│   │   └── add_to_production_order│   └── after_sales_service │       ├── vehicle_maintenance_services│       └── repair_services│└── manufacturing_department ├── production_planning │   └── specify_production_plan└── final_assembly_workshop 

要想使得外部也可以访问,这里就需要使用到关键字 pub

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}fn add_to_production_order() {}}mod after_sales_service {fn vehicle_maintenance_services() {}fn repair_services() {}}
}//---------------snip---------------------------

那么只在 pre_sales_service 前加上 pub 是否就可以了呢?编译试试看:

im01@Ubuntu:xiaomi_car$ cargo buildCompiling xiaomi_car v0.1.0 (/home/im01/Miracle/rust/xiaomi_car)
error[E0603]: function `add_to_production_order` is private--> src/lib.rs:25:57|
25 |             crate::sales_department::pre_sales_service::add_to_production_order();|                                                         ^^^^^^^^^^^^^^^^^^^^^^^ private function|
note: the function `add_to_production_order` is defined here--> src/lib.rs:7:9|
7  |         fn add_to_production_order() {}|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^error[E0603]: function `add_to_production_order` is private--> src/lib.rs:37:42|
37 |     sales_department::pre_sales_service::add_to_production_order();|                                          ^^^^^^^^^^^^^^^^^^^^^^^ private function|
note: the function `add_to_production_order` is defined here--> src/lib.rs:7:9|
7  |         fn add_to_production_order() {}|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^For more information about this error, try `rustc --explain E0603`.
error: could not compile `xiaomi_car` (lib) due to 2 previous errors

正如之前所说,外部无法访问指的外部是同层之外。因此 add_to_production_order 函数前也需要加上 pub

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}}mod after_sales_service {fn vehicle_maintenance_services() {}fn repair_services() {}}
}//---------------snip---------------------------

这样一来编译就没问题了。到这里相信大家已经粗略的感受到了在 rust 中作用域的概念。

4.4. super 关键字

这里换一种方式去调用 add_to_production_order

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}}mod after_sales_service {fn vehicle_maintenance_services() {}fn repair_services() {}}
}mod manufacturing_department {mod production_planning {fn specify_production_plan() {//add_to_production_order();crate::sales_department::pre_sales_service::add_to_production_order();// 等同于上一行super::super::sales_department::pre_sales_service::add_to_production_order();}}mod final_assembly_workshop {}
}pub fn sales_announcement() {sales_department::pre_sales_service::add_to_production_order();
}

此处便用到了 super 关键字,其作用想必各位从形势中也窥窃出一二来,没错 super 关键字的作用类似与 Linux 文件系统中的 .. 语法——到上一级目录,而相应的这里则是到上一级模块层。

为什么 rust 会多此一举的设计这样的关键字,原因很简单,当全文都在使用绝对路径,这样没错,但会显得代码冗长。而全文又使用相对路径,则会导致逻辑看起来混乱,难以阅读,一旦代码做过改动尤其是移动之后,将会带来相应的错误,而定位起来也较为不便,那么有了 super 的引入之后,我们很清楚的知道模块之间的关系,当代码整体移动时,也不必担心路径不对而需要修改调用路径。就是这样。

4.5. 将路径引入作用域

上面两个问题的解决方法虽然有效,但是仍然让代码显得冗长,这里将会介绍一个关键字 use 直接将需要的路径引入当前作用域,可以极大的简化代码的长度。

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}}
}mod manufacturing_department {mod production_planning {// 使用 use 关键字use crate::sales_department::pre_sales_service;fn specify_production_plan() {//add_to_production_order();pre_sales_service::add_to_production_order();}}
}

在当前作用域中增加 use 和路径类似于在文件系统中创建软连接(符号连接,symbolic link)。需要注意的是,use 只能对当前作用域范围内有效,若上面代码改为如下这样,则会无法使用到 use 引入进来的路径:

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}}
}// 使用 use 关键字
use crate::sales_department::pre_sales_service;mod manufacturing_department {mod production_planning {fn specify_production_plan() {//add_to_production_order();pre_sales_service::add_to_production_order();}}
}

事实上 use 也可以直接将其全部路径都引入,像这样:

mod sales_department {pub mod pre_sales_service {pub fn add_to_production_order() {}}
}mod manufacturing_department {mod production_planning {use crate::sales_department::pre_sales_service::add_to_production_order;fn specify_production_plan() {add_to_production_order();//pre_sales_service::add_to_production_order();}}
}

直接引入 add_to_production_order 函数的完整路径,这样的作法是允许的,而常常的做法会像之前一样,引入到其上一级,这样编写的代码会很明确看出来该函数是别的模块,而非当前模块。

4.6. as 关键字

这样引入完整路径会有什么问题吗?假设有两个同名函数不同模块,被同时引入呢?

答案是,rust 编译器将会告诉你这样的操作是不允许的。

那的确出现这样的情况怎么做?这时候 rust 提供了我们另外一个关键字 as,他可以为引入的变量或函数起别名,就像这样:

mod sales_department {pub mod pre_sales_service {pub fn test_func() {}}pub mod after_sales_service {pub fn test_func() {}}
}use crate::sales_department::pre_sales_service::test_func as pre_test_func;
use crate::sales_department::after_sales_service::test_func as after_test_func;
pub fn sales_announcement() {pre_test_func();after_test_func();
}

使用 as 关键字让两个本来会使用冲突的函数同时可以引入当前作用域。

4.7. pub use 重导出

mod sales_department {pub mod pre_sales_service {pub fn add_to_production_order() {}}
}pub use crate::sales_department::pre_sales_service;pub fn sales_announcement() {pre_sales_service::add_to_production_order();
}

这段代码与之前有所不同,这里引入路径使用了 pub use 而非 use,这样的作用是为了让外部代码也可以用这样的路径。

使用 use 关键字
在使用 use 引入路径时,外部代码调用 add_to_production_order 需要指定其完整路径xiaomi_car::sales_department::pre_sales_service::add_to_production_order() 才能够调用该函数;

使用 pub use 关键字
当使用 pub use 引入时,外部代码则可以通过 xiaomi_car::pre_sales_service::add_to_production_order()来调用该函数,仔细观察二者的区别,这样可以省略中间的一大堆具体路径,何乐而不为呢。

5. 引入的问题

5.1. 引入一个外部包

在之前我们编写了一个猜猜看游戏。那个项目使用了一个外部包,rand,来生成随机数。为了在项目中使用 rand,在 Cargo.toml 中加入了如下行:

rand = "0.8.5"

Cargo.toml 中加入 rand 依赖告诉了 Cargo 要从 crates.io 下载 rand 和其依赖,并使其可在项目代码中使用。

接着,为了将 rand 定义引入项目包的作用域,我们加入一行 use 起始的包名,它以 rand 包名开头并列出了需要引入作用域的项。回忆一下之前的 “生成一个随机数” 部分,我们曾将 Rng trait 引入作用域并调用了 rand::thread_rng 函数:

use rand::Rng;fn main() {let secret_number = rand::thread_rng().gen_range(1..=100);
}

crates.io 上有很多 Rust 社区成员发布的包,将其引入你自己的项目都需要一道相同的步骤:在 Cargo.toml 列出它们并通过 use 将其中定义的项引入项目包的作用域中。

注意 std 标准库对于你的包来说也是外部 crate。因为标准库随 Rust 语言一同分发,无需修改 Cargo.toml 来引入 std,不过需要通过 use 将标准库中定义的项引入项目包的作用域中来引用它们,比如我们使用的 HashMap

use std::collections::HashMap;

这是一个以标准库 cratestd 开头的绝对路径。

5.2. 嵌套路径来消除大量的 use 行

当需要引入很多定义于相同包或相同模块的项时,为每一项单独列出一行会占用源码很大的空间。例如猜猜看代码中有两行 use 语句都从 std 引入项到作用域:

// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--

相反,我们可以使用嵌套路径将相同的项在一行中引入作用域。这么做需要指定路径的相同部分,接着是两个冒号,接着是大括号中的各自不同的路径部分:

// --snip--
use std::{cmp::Ordering, io};
// --snip--

在较大的程序中,使用嵌套路径从相同包或模块中引入很多项,可以显著减少所需的独立 use 语句的数量!

我们可以在路径的任何层级使用嵌套路径,这在组合两个共享子路径的 use 语句时非常有用。例如有两个 use 语句:一个将 std::io 引入作用域,另一个将 std::io::Write 引入作用域:

use std::io;
use std::io::Write;

两个路径的相同部分是 std::io,这正是第一个路径。为了在一行 use 语句中引入这两个路径,可以在嵌套路径中使用 self

use std::io::{self, Write};

这一行代码便将 std::iostd::io::Write 同时引入作用域。

5.3. 通过 glob 运算符将所有的公有定义引入作用域

如果希望将一个路径下所有公有项引入作用域,可以指定路径后跟 *——glob 运算符:

use std::collections::*;

这个 use 语句将 std::collections 中定义的所有公有项引入当前作用域。使用 glob 运算符时请多加小心!Glob 会使得我们难以推导作用域中有什么名称和它们是在何处定义的。

glob 运算符经常用于测试模块 tests 中,这时会将所有内容引入作用域。

6. 将模块拆分为多文件

到目前为止,所有的例子都在一个文件中定义多个模块。当模块变得更大时,你可能想要将它们的定义移动到单独的文件中,从而使代码更容易阅读。

为了避免产生歧义,这里贴出笔者希望拆分的原本代码:

mod sales_department {pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}}pub mod after_sales_service {fn vehicle_maintenance_services() {}fn repair_services() {}}
}mod manufacturing_department {mod production_planning {fn specify_production_plan() {crate::sales_department::pre_sales_service::add_to_production_order();}}mod final_assembly_workshop {}
}pub fn sales_announcement() {
sales_department::pre_sales_service::add_to_production_order();
}

首先尝试将 sales_departmentmanufacturing_department 模块拆分出去,首先在 src 目录下创建 sales_department.rs 文件,为其添加如下内容:

pub mod pre_sales_service {fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}
}pub mod after_sales_service {fn vehicle_maintenance_services() {}fn repair_services() {}
}

[注]:这里是 src/sales_department.rs 文件

然后创建 manufacturing_department.rs 文件,为其添加如下内容:

mod production_planning {fn specify_production_plan() {crate::sales_department::pre_sales_service::add_to_production_order();}
}mod final_assembly_workshop {
}

[注]:这里是 src/manufacturing_department.rs 文件

然后再修改 src/lib.rs 文件内容:

mod sales_departmentmod manufacturing_departmentpub fn sales_announcement() {
sales_department::pre_sales_service::add_to_production_order();
}

这样就完成了这两个模块的拆分。因为编译器找到了 crate 根中名叫 sales_department 的模块声明,它就知道去搜寻 src/sales_department.rs 这个文件。

那如果还想继续拆分呢?要怎么做,其实道理相同,下面笔者展示将 sales_department 模块继续拆分成多个文件。

首先在 src 目录下创建 sales_department 目录,再进入 sales_department 目录,分别创建文件 pre_sales_service.rsafter_sales_service.rs,并为其添加如下内容:

fn model_consultation() {}fn purchase_plan_options() {}pub fn add_to_production_order() {}

[注]:这里是 src/sales_department/pre_sales_service.rs 文件

fn vehicle_maintenance_services() {}fn repair_services() {}

[注]:这里是 src/sales_department/after_sales_service.rs 文件

这样一来就将该模块继续拆分为更多的文件,这样拆分完后的文件目录结构如下。这个目录结构是不是很像我们的模块树。如果完全拆开,那么这就是模块树。

im01@Ubuntu:xiaomi_car$ tree
.
├── Cargo.lock
├── Cargo.toml
└──  src├── lib.rs├── manufacturing_department├── manufacturing_department.rs├── sales_department│   ├── after_sales_service.rs│   └── pre_sales_service.rs└── sales_department.rs

各位应该看到, 这里笔者提前创建了一个 manufacturing_department 目录,各位同学可以自己尝试将 manufacturing_department 模块继续拆分。这个技巧让你可以在模块代码增长时,将它们移动到新文件中。

注意我们只需在模块树中的某处使用一次 mod 声明就可以加载这个文件。一旦编译器知道了这个文件是项目的一部分(并且通过 mod 语句的位置知道了代码在模块树中的位置),项目中的其他文件应该使用其所声明的位置的路径来引用那个文件的代码,这在“引用模块项目的路径”部分有讲到。换句话说,mod 不是你可能会在其他编程语言中看到的 "include" 操作。

7. 小结

Rust 提供了将包分成多个 crate,将 crate 分成模块,以及通过指定绝对或相对路径从一个模块引用另一个模块中定义的项的方式。你可以通过使用 use 语句将路径引入作用域,这样在多次使用时可以使用更短的路径。模块定义的代码默认是私有的,不过可以选择增加 pub 关键字使其定义变为公有。

这一小节的文章很长,笔者写的自认为也太过啰嗦,能够坚持看完的你真的很厉害,请收下笔者赠与的小红花🌸,万分感激您的阅读,有任何疑问或问题还请不吝赐教~

下一篇《Rust语言基础16》


觉得这篇文章对你有帮助的话,就留下一个赞吧v*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用知识共享署名-非商业性-相同方式共享 4.0 国际许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/146339937

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com