Rust的模块化系统: 包Packages, 箱Crates, 和模块Modules
知乎
· · 160 次点击 ·
·
开始浏览
- 包 Packages: Cargo提供的让我们创建, 测试和分享Crates的工具.
- 箱 Crates: 提供类库或可执行文件的模块树
- 模块 Modules and use: 管理和组织路径, 及其作用域和访问权限
- 路径 Paths: 如结构体(structs), 函数(function), 或模块(module)等事物的命名方式
包(Packages)和箱(Crates)
包(Package)通过Cargo
创建. 每一个包(Package)都有一个Cargo.toml
文件. 包(Package)包含箱(Crates)的规则如下:
- 只能包含0或1个类库箱(library crates)
- 可以包含任意多个二进制箱(binary crates)
- 至少有一个箱(Crate), 可以是类库箱(library crates), 也可以是二进制箱(binary crates)
创建二进制包(binary package)
❯ cargo new my-project
Created binary (application) `my-project` package
❯ tree my-project
my-project
├── Cargo.toml
└── src
└── main.rs
创建类库包(library package)
❯ cargo new --lib my-lib
Created library `my-lib` package
❯ tree my-lib
my-lib
├── Cargo.toml
└── src
└── lib.rs
默认, 一个箱(crate):
- src/main.rs 是二进制箱(binary crate)的根文件, 该箱(crate)与包(package)同名
- src/lib.rs 是类库箱(library crate)的根文件, 该箱(crate)与包(package)同名
多个二进制箱(binary crates): 在src/bin
目录下创建.rs
文件, 每个文件对应一个二进制箱(binary crate).
模块Modules
模块通过关键字mod
加模块定义, 例如:
// Filename: src/lib.rs
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
文件src/main.rs
和src/lib.rs
, 对应的模块是crate
, 箱(crate)的模块结构(module structure), 也叫做模块树(module tree):
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
注: 模块crate
默认存在, 不需要通过关键字mod
方式来定义
路径Paths
与文件系统类似, 文件系统的根节点是/
, 箱(crate)的根节点是crate
.
- 绝对路径, 从箱(crate)的根节点开始, 箱(crate)的名称, 或
crate
- 相对路径, 从当前模块开始, 可以使用
self
,super
// 绝对路径 Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径 Relative path
front_of_house::hosting::add_to_waitlist();
访问权限
- 所有元素, 函数functions, 方法methods, 结构体structs, 枚举enum, 模块modules, 常量constants, 默认是私有的, 对外公开(public), 需要通过关键字
pub
声明- 即便是共有的结构体(public structs), 内部的元素(fields)和方法(methods)仍是私有的(private)
- 共有的枚举(public enums), 其所有变天(variants)也同为共有(public)
- 父模块中的元素, 不能使用子模块中的私有元素
- 子模块中的元素, 可以使用父模块的元素
use
使用关键字use
简化路径Paths, 类似文件系统中的'symbolic link'.
一些惯常用法
调用其它模块函数时, 通过use
引入其所在的模块(module)
use some_mod;
fn main() {
some_mod::some_fn();
}
调用其它模块结构体struct, 枚举enum,通过全路径引入,
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
有命名冲突时, 引入父模块
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
}
fn function2() -> io::Result<()> {
// --snip--
}
或用as
解决命名冲突的问题
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
}
fn function2() -> IoResult<()> {
// --snip--
}
引入同一个模块module或包package中的多个元素
use std::{cmp::Ordering, io};
use std::io::{self, Write}; // 引入 std::io 和 std::io::Write
引入模块下所有共有元素, 需谨慎使用, 一般在测试时或预加载时使用
use std::collections::*;
re-exporting names with pub use
(暂且跳过)
使用外部包(External Packages)
在文件Cargo.toml
中添加依赖[dependencies]
, Cargo从crates.io下载所需要的依赖包.
[dependencies]
rand = "0.5.5"
引入rand
中的Rng
特性(trait)
use rand::Rng;
fn main() {
let secret_number = rand::thread_rng().gen_range(1, 101);
}
160 次点击
加入收藏