From 92223ec637811068b4815201a21f0965a155cbeb Mon Sep 17 00:00:00 2001 From: sunface Date: Wed, 23 Mar 2022 17:33:39 +0800 Subject: [PATCH] Add zh/crate-module --- zh-CN/src/crate-module/crate.md | 112 ++++++++++++++++- zh-CN/src/crate-module/module.md | 194 ++++++++++++++++++++++++++++++ zh-CN/src/crate-module/use-pub.md | 69 +++++++++++ 3 files changed, 374 insertions(+), 1 deletion(-) diff --git a/zh-CN/src/crate-module/crate.md b/zh-CN/src/crate-module/crate.md index e66fb06..b748db4 100644 --- a/zh-CN/src/crate-module/crate.md +++ b/zh-CN/src/crate-module/crate.md @@ -1 +1,111 @@ -# Crate +# Package and Crate +`package` 是你通过 `Cargo` 创建的工程或项目,因此在 `package` 的根目录下会有一个 `Cargo.toml` 文件。 + +1. 🌟 创建一个 `package`,拥有以下目录结构: +```shell +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +```toml +# in Cargo.toml +[package] +name = "hello-package" +version = "0.1.0" +edition = "2021" +``` + +> 注意! 我们会在包与模块中使用上面的项目作为演示,因此不要删除 + +2. 🌟 创建一个 package,拥有以下目录结构: +```shell +. +├── Cargo.toml +└── src + └── lib.rs + +1 directory, 2 files +``` + +```toml +# in Cargo.toml +[package] +name = "hello-package1" +version = "0.1.0" +edition = "2021" +``` + +> 该项目可以安全的移除 + +3. 🌟 +```rust,editable +/* 使用你的答案填空 */ + +// Q: package 1# 和 2# 的区别是什么 ? +// A: __ +``` + + +## 包Crate +一个包可以是二进制也可以一个依赖库。每一个包都有一个包根,例如二进制包的包根是 `src/main.rs`,库包的包根是 `src/lib.rs`。包根是编译器开始处理源代码文件的地方,同时也是包模块树的根部。 + +在 package `hello-package` 中,有一个二进制包,该包与 `package` 同名 : `hello-package`, 其中 `src/main.rs` 是该二进制包的包根. + +与 `hello-package` 类似, `hello-package1` 同样包含一个包,但是与之前的二进制包不同,该 package 包含的是库包,其中 `src/lib.rs` 是其包根. + +4. 🌟 +```rust,editable +/* 填空 */ + +// Q: package `hello-package1` 中的库包名称是? +// A: __ +``` + + +5. 🌟🌟 为 `hello-package` 添加一个库包,并且完成以下目录结构的填空: +```shell,editable +# 填空 +. +├── Cargo.lock +├── Cargo.toml +├── src +│   ├── __ +│   └── __ +``` + +在上一个步骤后,我们的 `hello-package` 中已经存在两个包:一个二进制包和一个库包,两个包的名称都与 package 相同:`hello-package`。 + + + +6. 🌟🌟🌟 一个 package 最多只能包含一个库包,但是却可以包含多个二进制包:通过将二进制文件放入到 `src/bin` 目录下实现: **该目录下的每个文件都是一个独立的二进制包,包名与文件名相同,不再与 package 的名称相同。**. + +```shell,editable +# 创建一个 a package 包含以下包: +# 1. 三个二进制包: `hello-package`, `main1` and `main2` +# 2. 一个库包 +# 并完成以下目录结构的填空 +. +├── Cargo.toml +├── Cargo.lock +├── src +│ ├── __ +│ ├── __ +│ └── __ +│ └── __ +│ └── __ +├── tests # 存放集成测试文件的目录 +│ └── some_integration_tests.rs +├── benches # 存放 benchmark 文件的目录dir for benchmark files +│ └── simple_bench.rs +└── examples # 存放示例文件的目录 + └── simple_example.rs +``` + +可以看到,上面的 package 结构非常标准,你可以在很多 Rust 项目中看到该结构的身影。 + + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :) \ No newline at end of file diff --git a/zh-CN/src/crate-module/module.md b/zh-CN/src/crate-module/module.md index b785ceb..41caa2b 100644 --- a/zh-CN/src/crate-module/module.md +++ b/zh-CN/src/crate-module/module.md @@ -1 +1,195 @@ # Module +在 Rust 语言圣经中,我们已经深入讲解过[模块module](https://course.rs/basic/crate-module/module.html),这里就不再赘述,直接开始我们的练习。 + +之前我们创建了一个 package `hello-package`,它的目录结构在经过多次修改后,变成了以下模样: + +```shell +. +├── Cargo.toml +├── src +│   ├── lib.rs +│   └── main.rs +``` + +下面,我们来为其中的库包创建一些模块,然后在二进制包中使用这些模块。 + +1. 🌟🌟 根据以下的模块树描述实现模块 `front_of_house` : +```shell +库包的根(src/lib.rs) + └── front_of_house + ├── hosting + │ ├── add_to_waitlist + │ └── seat_at_table + └── serving + ├── take_order + ├── serve_order + ├── take_payment + └── complain +``` + +```rust,editable +// 填空 +// in __.rs + +mod front_of_house { + // 实现此模块 +} +``` + + +2. 🌟🌟 让我们在库包的根中定义一个函数 `eat_at_restaurant`, 然后在该函数中调用之前创建的函数 `eat_at_restaurant` + +```rust +// in lib.rs + +// 填空并修复错误 + +// 提示:你需要通过 `pub` 将一些项标记为公有的,这样模块 `front_of_house` 中的项才能被模块外的项访问 +mod front_of_house { + /* ...snip... */ +} + +pub fn eat_at_restaurant() { + // 使用绝对路径调用 + __.add_to_waitlist(); + + // 使用相对路径调用 + __.add_to_waitlist(); +} +``` + +3. 🌟🌟 我们还可以使用 `super` 来导入父模块中的项 +```rust,editable +// in lib.rs + +mod back_of_house { + fn fix_incorrect_order() { + cook_order(); + // 使用三种方式填空 + //1. 使用关键字 `super` + //2. 使用绝对路径 + __.serve_order(); + } + + fn cook_order() {} +} +``` + + +### 将模块分离并放入独立的文件中 +```rust +// in lib.rs +pub mod front_of_house { + pub mod hosting { + pub fn add_to_waitlist() {} + + pub fn seat_at_table() -> String { + String::from("sit down please") + } + } + + pub mod serving { + pub fn take_order() {} + + pub fn serve_order() {} + + pub fn take_payment() {} + + // 我猜你不希望顾客听到你在抱怨他们,因此让这个函数私有化吧 + fn complain() {} + } +} + +pub fn eat_at_restaurant() -> String { + front_of_house::hosting::add_to_waitlist(); + + back_of_house::cook_order(); + + String::from("yummy yummy!") +} + +pub mod back_of_house { + pub fn fix_incorrect_order() { + cook_order(); + crate::front_of_house::serving::serve_order(); + } + + pub fn cook_order() {} +} +``` + +4. 🌟🌟🌟🌟 请将上面的模块和代码分离到以下目录文件中e : +```shell +. +├── Cargo.toml +├── src +│   ├── back_of_house.rs +│   ├── front_of_house +│   │   ├── hosting.rs +│   │   ├── mod.rs +│   │   └── serving.rs +│   ├── lib.rs +│   └── main.rs +``` + +```rust,editable +// in src/lib.rs + +// IMPLEMENT... +``` + +```rust,editable +// in src/back_of_house.rs + +// IMPLEMENT... +``` + + +```rust,editable +// in src/front_of_house/mod.rs + +// IMPLEMENT... +``` + +```rust,editable +// in src/front_of_house/hosting.rs + +// IMPLEMENT... +``` + +```rust,editable +// in src/front_of_house/serving.rs + +// IMPLEMENT... +``` + +### 从二进制包中访问库包的代码 +**请确保你已经完成了第四题,然后再继续进行.** + +当到底此处时,你的项目结构应该如下所示: +```shell +. +├── Cargo.toml +├── src +│   ├── back_of_house.rs +│   ├── front_of_house +│   │   ├── hosting.rs +│   │   ├── mod.rs +│   │   └── serving.rs +│   ├── lib.rs +│   └── main.rs +``` + +5. 🌟🌟🌟现在我们可以从二进制包中发起函数调用了. + +```rust,editable +// in src/main.rs + +// 填空并修复错误 +fn main() { + assert_eq!(__, "sit down please"); + assert_eq!(__,"yummy yummy!"); +} +``` + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :) \ No newline at end of file diff --git a/zh-CN/src/crate-module/use-pub.md b/zh-CN/src/crate-module/use-pub.md index 60c6894..065f24c 100644 --- a/zh-CN/src/crate-module/use-pub.md +++ b/zh-CN/src/crate-module/use-pub.md @@ -1 +1,70 @@ # use and pub +1. 🌟 使用 `use` 可以将两个同名类型引入到当前作用域中,但是别忘了 `as` 关键字. + +```rust,editable +use std::fmt::Result; +use std::io::Result; + +fn main() {} +``` + +2. 🌟🌟 如果我们在使用来自同一个包或模块中的多个不同项,那么可以通过简单的方式将它们一次性引入进来 + +```rust,editable + +// 使用两种方式填空 +// 不要添加新的代码行 +use std::collections::__; + +fn main() { + let _c1:HashMap<&str, i32> = HashMap::new(); + let mut c2 = BTreeMap::new(); + c2.insert(1, "a"); + let _c3: HashSet = HashSet::new(); +} +``` + +### 使用 `pub use` 进行再导出 + +3. 🌟🌟🌟 在之前创建的`hello-package` 的库包中, 添加一些代码让下面的代码能够正常工作 +```rust,editable +fn main() { + assert_eq!(hello_package::hosting::seat_at_table(), "sit down please"); + assert_eq!(hello_package::eat_at_restaurant(),"yummy yummy!"); +} +``` + + +### pub(in Crate) +有时我们希望某一个项只对特定的包可见,那么就可以使用 `pub(in Crate)` 语法. + +#### 示例 +```rust,editable +pub mod a { + pub const I: i32 = 3; + + fn semisecret(x: i32) -> i32 { + use self::b::c::J; + x + J + } + + pub fn bar(z: i32) -> i32 { + semisecret(I) * z + } + pub fn foo(y: i32) -> i32 { + semisecret(I) + y + } + + mod b { + pub(in crate::a) mod c { + pub(in crate::a) const J: i32 = 4; + } + } +} +``` + +### 完整代码 +至此,包与模块章节已经结束,关于 `hello-package` 的完整代码可以在[这里](https://github.com/sunface/rust-by-practice/tree/master/practices/hello-package) 找到. + + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :) \ No newline at end of file