模块与包
包(crate)
Rust的crate在于其他语言中被称为“package”或“library”。Rust的crate是一个独立的可编译单元。
使用cargo既可创建一个crate,具体参见《Rust简介 - > Cargo》
值得注意:一个工程下可以包含多个crate。
crate包内可以有一个main.rs文件,其中包含main函数。也就是说,若crate拥有main函数,则该crate被编译后即可运行。
模块(module)
Rust中使用mod
在一个文件中定义一个模块,或引用另外一个文件中的模块。
关于模块的特性:
- 每个 crate 中,默认实现了一个隐式的 根模块(root module);
- 模块可以嵌套;
- 模块的命名风格也是 lower_snake_case,跟其它的 Rust 的标识符一样;
- 模块中可以写任何合法的 Rust 代码;
定义一个模块
例:定义模块。在lib.rs 中,添加代码。
mod aaa {
const X: i32 = 10;
fn print_aaa() {
println!("{}", 42);
}
}
嵌套的模块
mod aaa {
const X: i32 = 10;
fn print_aaa() {
println!("{}", 42);
}
mod bbb {
fn print_bbb() {
println!("{}", 37);
}
}
}
树状嵌套的mod。
mod aaa {
const X: i32 = 10;
fn print_aaa() {
println!("{}", 42);
}
mod bbb {
fn print_bbb() {
println!("{}", 37);
}
}
}
mod ccc {
fn print_ccc() {
println!("{}", 25);
}
}
可以看到使用mod在一个文件内可以以树形形式定义模块。
在外部文件定义模块
在abc.rs文件中
pub fn print_abc() {
println!("abc");
}
在main.rs模块中
mod abc;
use abc::print_abc;
fn main () {
print_abc();
}
abc.rs
中没有使用mod xxx {}
这样包裹起来。使用mod xxx;
相当于把xxx.rs
文件用mod xxx {}
包裹起来了。
模块可见性
默认模块不对包外暴露模块以及模块内的函数和结构体。使用pub
,使其对外暴露。
- 公有的可被父级模块访问。
- 私有以及当前模块与子模块访问。
- 同级项可以相互访问。
mod outermost {
pub fn middle_function() {}
fn middle_secret_function() {}
mod inside {
pub fn inner_function() {}
fn secret_function() {}
}
}
// try_me可识别到outermost
fn try_me() {
outermost::middle_function(); // 访问同级公有函数
outermost::middle_secret_function(); // 编译错误,不可访问私有函数。
outermost::inside::inner_function(); // 编译错误,不可访问私有模块的公有函数。
outermost::inside::secret_function(); // 编译错误,不可访问私有模块的私有函数。
}
函数的调用
模块内的可访问函数方式:
模块名::函数名
模块名::结构体名
详解use
例:
pub mod a {
pub mod series {
pub mod of {
pub fn nested_modules() {}
}
}
}
use a::series::of::nested_modules;
fn main() {
nested_modules();
// 否则要这样调用:a::series::of::nested_modules(); 非常麻烦。
}
例:
enum TrafficLight {
Red,
Yellow,
Green,
}
use TrafficLight::{Red, Yellow};
fn main() {
let red = Red;
let yellow = Yellow;
let green = TrafficLight::Green; // 编译不通过
}
例:
enum TrafficLight {
Red,
Yellow,
Green,
}
use TrafficLight::*; // 引入TrafficLight中所有元素
fn main() {
let red = Red;
let yellow = Yellow;
let green = Green;
}
使用super访问模块
访问模块与访问文件是一致的,都有两种方式:
- 绝对路径访问
- 相对路径访问
super
表示父包。super
关键字类似于文件系统用于表示相对路径的..
来看一个场景,如下app模块中,service模块的call方法希望访问client模块的connect方法。
mod app {
mod client {
pub fn connect() {
println!("connecting!")
}
}
mod service {
fn call() {
// 尝试调用app::client::connect();
}
}
}
使用绝对路径方式访问:use后面跟函数的全路径。
mod app {
mod client {
pub fn connect() {
println!("connecting!")
}
}
mod service {
// 相当于使用全路径
use app::client::connect;
fn call() {
connect();
}
}
}
使用相对路径方式访问:使用super表示父包。
mod app {
mod client {
pub fn connect() {
println!("connecting!")
}
}
mod service {
// 相当于使用相对路径
use super::client::connect;
fn call() {
connect();
}
}
}
工程中的包定义
Rust中包可以由一直更加美观的方式定义,即每个目录定义为一个mod。即,
- 目录名作为包名。
- 目录下通过mod.rs文件说明该目录为包。
- mod.rs中为此包暴露的方法与子包。
例:crate包的名称为test-lib。其中有若干个包。package1包内有package2包与package3包,另外package1包有pub fn1函数,fn2函数。
test-lib/
|----src/
|----lib.rs
|----package1/
|----mod.rs
|----package2/
|----mod.rs
|----package3
|----mod.rs
这里可以直接参考Rust实际工程:https://github.com/pingcap/tikv/blob/master/src/lib.rs