企业建网站费用/必应搜索引擎首页

企业建网站费用,必应搜索引擎首页,昆明网站建设方案优化,有没有做网站源代码 修改的文章目录 1. 前言2. 包和 Crate3. 定义模块以及模块之间的关系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 行…

文章目录

  • 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】集合的使用——Rust语言基础16》


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务架构中的API网关:Spring Cloud与Kong/Traefik等方案对比

微服务架构中的API网关:Spring Cloud与Kong/Traefik等方案对比 一、API 网关的概念二、API 网关的主要功能2.1 统一入口与路由转发2.2 安全与权限控制2.3 流量管理与容错2.4 API 管理与聚合2.5 监控与日志2.5 协议转换与适配2.6 控制平面与配置管理 三、API 网关选型…

NewStar CTF web wp

文章目录 week1headach3会赢吗智械危机谢谢皮蛋PangBai 过家家(1) week3include meblindsql1臭皮的计算机臭皮踩踩背这照片是你吗 week4Pangbai过家家四blindsql2chocolateezcmsssezpollute隐藏的密码 weeek5pangbai过家家(5)redissqlshell臭皮吹泡泡臭皮…

Linux驱动开发-①中断②阻塞、非阻塞IO和异步通知

Linux驱动开发-①中断②阻塞、非阻塞IO和异步通知 一,中断1.中断的流程2.上半部和下半部2.1上半部2.2下半部2.2.1 tasklet2.2.2 工作队列 3.按键延时消抖中断程序 二,阻塞和非阻塞IO和异步通知1.阻塞IO1.1 常见结构11.2 常见结构2 2.非阻塞IO2.1 驱动结构…

Docker和Dify学习笔记

文章目录 1 docker学习1.1 基本命令使用1.1.1 docker ps查看当前正在运行的镜像1.1.2 docker stop停止容器1.1.3 docker compose容器编排1.1.4 docker网络[1] 进入到容器里面敲命令[2] docker network ls[3] brige网络模式下容器访问宿主机的方式 2 Dify的安装和基础使用2.1 下…

探秘Transformer系列之(16)--- 资源占用

探秘Transformer系列之(16)— 资源占用 文章目录 探秘Transformer系列之(16)--- 资源占用0x00 概述0x01 背景知识1.1 数据类型1.2 进制&换算数字进制存储度量换算 1.3 参数显存占用有参数的层无参数的层所需资源 1.4 计算量 0…

jaeger安装和简单使用

文章目录 jaeger安装和使用什么是jaegerjaeger安装 jaeger安装和使用 什么是jaeger 官网:https://www.jaegertracing.io/ Jaeger 是一个分布式追踪系统。Jaeger的灵感来自 Dapper 和 OpenZipkin,是一个由 Uber 创建并捐赠给 云原生计算基金会&#xf…

【Mybatis-plus】在mybatis-plus中 if test标签如何判断 list不为空

博主介绍:✌全网粉丝22W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

【递归,搜索与回溯算法篇】- 名词解释

一. 递归 1. 什么是递归? 定义: 函数自己调用自己的情况关键点: ➀终止条件: 必须明确递归出口,避免无限递归 ➁子问题拆分: 问题需能分解成结构相同的更小的子问题缺点: ➀栈溢出风险&#x…

大屏技术汇集【目录】

Cesium 自从首次发布以来,经历了多个版本的迭代和更新,每个版本都带来了性能改进、新功能添加以及对现有功能的优化。以下是 Cesium 一些重要版本及其主要特点: 主要版本概述 Cesium 1.0 (2012年) 初始版本发布,确立了Cesium作为…

图解AUTOSAR_CP_EEPROM_Abstraction

AUTOSAR EEPROM抽象模块详细说明 基于AUTOSAR标准的EEPROM抽象层技术解析 目录 1. 概述 1.1 核心功能1.2 模块地位2. 架构概览 2.1 架构层次2.2 模块交互3. 配置结构 3.1 主要配置容器3.2 关键配置参数4. 状态管理 4.1 基本状态4.2 状态转换5. 接口设计 5.1 主要接口分类5.2 接…

C++相关基础概念之入门讲解(下)

1. 引用 ​ int main() {const int a10;int& aaa;aa;cout<<aa<<endl; } 引用 不是新定义一个变量&#xff0c;而 是给已存在变量取了一个别名 &#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用的变量 共用同一块内存空间&#xff08;初…

注意力机制,本质上是在做什么?

本文以自注意机制为例&#xff0c;输入一个4*4的矩阵 如下&#xff1a; input_datatorch.tensor([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16] ],dtypetorch.float) 得到Q和K的转置如下。 此时&#xff0c;计算QK^T ,得到如下结果 第一行第一个位置就是第一条样本和第…

Windows搭建免翻墙的BatteryHistorian

文章参考 GitCode - 全球开发者的开源社区,开源代码托管平台 免翻墙的BatteryHistorian主要原理&#xff1a;修改go源码 1.安装Java环境 1.点击下载 Java JDK&#xff0c;并安装,一路next 2.java -version 检验是否安装成功 2.安装Git工具 1、点击下载 Git&#xff0c;并…

WRF/Chem 模式技术解读:为大气污染治理提供有力支撑

技术点目录 第一部分、WRF-Chem模式应用案例和理论基础第二部分、Linux环境配置及WRF-CHEM第三部分、WRF-Chem模式编译&#xff0c;排放源制作第四部分、WRF-Chem数据准备&#xff08;气象、排放、初边界条件等&#xff09;&#xff0c;案例实践第五部分、模拟结果提取、数据可…

ccfcsp2701如此编码

//如此编码 #include<iostream> using namespace std; int main(){int n,m;cin>>n>>m;int a[21],b[21],c[21];for(int i1;i<n;i){cin>>a[i];}c[0]1;for(int i1;i<n;i){c[i]c[i-1]*a[i];}b[1](m%c[1])/c[0];int s1,s20;for(int i2;i<n;i){s2s2…

74HC04(反相器)和74HC14(反相器、施密特触发器)的区别

74HC04和74HC14的具体区别详解 同样具有反相器功能&#xff0c;你知道74HC04和74HC14的具体区别吗&#xff1f; 74HC04 对于74HC04很好理解&#xff0c;输入低电平&#xff0c;输出高电平&#xff1b;输入高电平&#xff0c;输出低电平。 建议操作条件&#xff1a; 下图是TI的…

第十四次CCF-CSP认证(含C++源码)

第十四次CCF-CSP认证 卖菜满分思路 买菜满分思路 再卖菜满分题解&#xff08;差分约束&#xff09;solution 1(枚举 correct but 超时)solution 2(正解) 卖菜 题目链接 满分思路 就是模拟一下这个调整第二天菜价的过程&#xff0c;其中对于两种只有一个邻居的情况下做出调整&…

CCBCISCN复盘

AWDP – ccfrum 自己搭了一下环境, 复现一下这道题目, 之前比赛的时候完全没想到这个漏洞要怎么打, 修也不知道要怎么修, 就仅仅是对用户名的账号和密码进行了一下过滤, 完全没起到作用, 唉, 实在太菜 如果想要尝试复现的话可以尝试拉取这个镜像, 我打完之后就直接把这个容器给…

VS010生成可由MATLAB2016调用的DLL文件方法

亲测实用&#xff0c;不用配置杂七杂八的依赖项 1&#xff1a;新建Win32的DLL输出项目 2&#xff1a;修改为release模式 3&#xff1a;添加calc.cpp文件&#xff0c;即要导出的函数myadd&#xff1a; #include "calc.h" __declspec(dllexport) int myadd(int a,in…

优选算法系列(3.二分查找 )

目录 一.二分查找&#xff08;easy&#xff09; 题目链接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; 代码&#xff1a; 二.在排序数组中查找元素的第⼀个和最后⼀个位置&#xff08;medium&#xff09; 题目链接&#xff1a;34.…