mirror of
https://github.com/sunface/rust-by-practice.git
synced 2025-06-23 12:39:42 +00:00
Add zh/crate-module
This commit is contained in:
@ -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 :)
|
@ -1 +1,195 @@
|
|||||||
# Module
|
# 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 :)
|
@ -1 +1,70 @@
|
|||||||
# use and pub
|
# 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<i32> = 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 :)
|
Reference in New Issue
Block a user