Rust模块系统:
包(Package):一个用于构建、测试并分享单元包的Cargo功能。
单元包(crate): 一个用于生成库或可执行文件的树形模块结构。
模块(module): 它们被用于控制文件结构、作用域及路径的私有性。
路径(path):一种用于命名条目的方法,这些条目包括结构体、函数和模块等。
总结:模块系统的作用主要是用来管理和组织代码。代码既可以作为公共接口部分供他人使用,也可以作为私有化实现细节,保留代码修改的权利。
包和单元包
包(可以类比前端工程):
1. Cargo.toml类比package.json。Cargo.toml文件描述构建当前工程的单元包的信息,同时还有引用第三方依赖的信息。
2. 包中单元包(二进制单元包和库单元包):
src/main.ts: 二进制单元包的根节点 ,且二进制单元包与包拥有相同的名称。在src/bin路径下添加源文件来创建出更多的二进制单元包
src/lib.rs:库单元包的根节点。和包拥有过相同的名称。一个包中只能拥有最多一个库单元包。
3. 理解二进制单元包和库单元包:二进制单元包是为了开发当前业务系统;库单元包类比开发可以通过npm安装的依赖组件。
包和单元包的规则:
1. 一个包中只能拥有最多一个库单元包。
2. 包可以拥有任意多个二进制单元包。
3. 包内必须存在至少一个单元包(库单元包或二进制单元包)。
总结:
1. 包可以类比前端工程
2. 单元包分为二进制单元包和库单元包。二进制单元包就是开发当前业务系统;库单元包是为了开发组件库(类比npm组件)。
模块、条目和路径:
模块划分:
模块将单元包内的代码按照可读性与易用性来进行分组。模块关键字mod
模块包含条目,条目可以是函数、结构体、模块。可以控制条目的私有性和公有性(pub关键字)。
// src/lib.rs 库单元包,拥有和库相同的名称
// 将库单元包通过模块进行划分,模块中又可以包含函数(fn定义)、和子节点(hosting)
// front_of_house 称为 hosting的父节点
mod front_of_house{
mod hosting{
fn add_to_waitlist(){
}
fn seat_at_table(){
}
}
}
来自《Rust权威指南》
模块,我们可以将相关的定义分到一组。src/main.rs 与src/lib.rs 被称作单元包的根节点,因为这两个文件的内容各自组成了一个名为crate的模块,并位于单元包模块结构的根部。这个模块结构也被称为模块树(module tree)
模块树的作用类比目录结构,这种设计主要作用还是为了方便查找代码所在位置,也能够避免命名冲突,因为两个相同名称的子节点在树的不同分支上。
路径:
路径的作用是用于查找模块里的条目
路径有两种形式:
• 使用单元包名或字面量crate从根节点开始的绝对路径。
• 使用self、super或内部标识符从当前模块开始的相对路径。
绝对路径与相对路径都由至少一个标识符组成,标识符之间使用双冒号(::)分隔。
mod front_of_house{
pub mod hosting{
pub fn add_to_waitlist(){
}
fn seat_at_table(){
}
}
mod seving{
fn take_order(){}
fn serve_order(){}
fn take_payment(){}
}
}
pub fn eat_at_restaurant(){
// 绝对路径,以包名(crate关键字指向包名)开头
crate::front_of_house::hosting::add_to_waitlist()
// 使用相对路径,以模块开头
front_of_house::hosting::add_to_waitlist();
}
crate 这里是字面量,表示当前库单元包的包名。
想要使用模块的函数,模块内的条目必须使用pub关键字修饰。
大部分的Rust开发者会更倾向于使用绝对路径,因为我们往往会彼此独立地移动代码的定义与
调用代码。
总结:
1. 模块的作用主要是功能相关的代码分组到一起
2. 条目是模块的组成部分,包含变量、结构体、枚举、子节点等
3. 路径是访问条目的路径。是条目在模块树的节点的路径。
路径的绝对和相对:
绝对路径:
关键字crate指向包名。路径是从包名开始,根模块的模块名和包名相同。
相对路径:
关键字super:父模块开始构造相对路径,类似于在文件系统中使用..语法。
fn serve_order(){
}
mod back_of_house{
fn fix_incorrect_order(){
cook_order();
super::serve_order(); // super指向了上一层模块
}
fn cook_order(){}
}
pub、结构体和枚举:
pub可以定义结构体的部分属性是pub的,没定义的默认是私有的
pub 直接修饰枚举定义,枚举的所有变体都是公有的
pub、use:
use将路径导入作用域
借助use关键字来将路径引入作用域,并像使用本地条目一样来调用路径中的条目。
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist(); // 从hosting模块开始
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
在单元包的根节点下添加use crate::front_of_house::hosting,就如同hosting模块被定义在根节点下一样。
使用use来指定相对路径路径的开始处使用关键字self:(未来可能会去掉)
use self::front_of_house::hosting;
引入路径问题:
惯用方式是use后面的路径到条目的父级路径
use将结构体、枚举和其他条目引入作用域时,习惯于通过指定完整路径的方式引入
as关键字
可以解决use引入同名条目的时候,将名字修改为别名。
pub use重导出名称
pub use crate::front_of_house::hosting; // pub use使一个名称可以在新作用域中被其他任意代码使
用
Cargo.toml
[dependencies] 表示外部依赖。需要手动写依赖和依赖的版本
[dependencies]
rand = "0.5.5"
Cargo从crates.io上下载rand及相关的依赖包
不知道后面会不会出类似npm的依赖安装工具
use rand::Rng;
fn main() {
let secret_number = rand::thread_rng().gen_range(1, 101);
}
use 引入的是Rng trait。 因为rand::thread_rng() 函数是继承了Rng Trait,所以,必须要使用use引入下。(这里有点繁琐了,为什么不是直接引入rand)
标准库(std)已经被内置到了Rust语言中,不需要Cargo.toml文件中引入,但是需要use引入。
use多分支引入:
use std::{cmp::Ordering, io};
use std::io::{self, Write}; // 表示引入io和io::Write
use使用通配符:
use std::collections::*;
定义在std::collections内的所有公共条目都导入当前作用域,然而这种使用方法存在弊端,就是不清楚该作用域都有哪些条目。
模块拆分到文件:
// src/lib.rs
mod front_of_house; // 区别于模块定义,这里让rust去模块文件中查找条目
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant(){
hosting::add_to_waitlist();
}
// src/front_of_house.rs
pub mod hosting{
pub fn add_to_waitlist(){}
}
关键是mod front_of_house; 拆分到不同文件的关键。新建的src/front_of_house.rs文件里的代码就只包含了子节点和子节点的函数。
然后,创建名字为front_of_house的文件夹,在该文件夹下创建hosting.rs文件,将函数add_to_waitlist函数的定义放进去。这样就完成了模块拆分到不同的文件中。
总结:
模块拆分到文件,采用了类似文件目录的方法:文件(模块同名)用来存储其子节点的条目,或者通过mod +子节点名称方式告诉rust去查找子节点模块。模块同名文件夹存储子节点的条目的文件。
总结:
文章引字《Rust权威指南》一书。通过整理让概念和知识点更加条理清晰。
本章都是概念知识很简单,但是需要把知识点梳理清楚