Rust|Package,Crate,Module
1. Rust代码组织
代码组织可以决定哪些细节可以暴露,哪些细节是私有的,作用域内哪些名称有效。。。
模块系统:
- package(包):cargo特性,让你构建、测试、共享crate
- crate(单元包):一个模块数,它可以产生一个library或可执行文件
- module(模块)、use:让你控制代码的组织、作用域、私有路径
- path(路径):为struct、function或module等命名的方式
1.1 package和crate
对于一个package,有以下规定:
- 包含一个Cargo.toml,它描述了如何构建这些crates
- 最多包含一个library crate
- 可以包含任意数量的binary crate
- 至少包含一个crate(library或binary)
crate有两种类型:binary和library,有一个crate root,是源代码文件,Rust编译器从这里开始,组成crate的根module
1.2 cargo的惯例
创建一个新的Rust项目,命名为my-project
cargo new my-project |
出现文件src/main.rs
,该文件是binary crate的crate root,crate名与package名相同
若出现src/lib.rs
(一般不会),该文件表示package包含一个library crate,其为library crate的crate root,crate名与package名相同
cargo把crate root文件交给rustc来构建library或binary
一个package可以同时包含src/main.rs
和src/lib.rs
,名称与package名相同。一个package可以同时有多个binary crate,文件必须放在src/bin
中,每个文件是单独的binary crate
1.3 定义module来控制作用域和私有性
使用module有以下好处:
- 在crate内,将代码进行分组
- 增加可读性,易于复hexo
- 控制项目(item)的私有性(public、private)
mod front_of_house |
2. Path路径
为了在Rust的模块中找到某个条目,需要使用路劲。
路径有两种形式:
- 绝对路径:从crate root开始,使用crate名或字面值crate
- 相对路径:从当前模块开始,使用self,super或当前模块的标识符
路径至少由一个标识符组成,标识符之间使用::
以下例子来自文件src/lib.rs
,即拥有lib crate root
mod front_of_house |
2.1 Privacy Boundary私有边界
模块不仅可以组织代码,还可以定义私有边界。如果想把函数
或者struct
等设为私有,可以将它放在某个模块中。定义规则:
- Rust中的所有条目(函数,方法,struct,enum,模块,常量)默认是私有的。
- 父级模块无法访问子模块中的私有条目。
- 子模块可以使用所有祖先条目。
- 同级条目可以互相访问。
- 使用
pub
关键字,将条目标记为公共。
2.2 super
关键字
利用super
关键字来访问父级模块路径中的内容,类似文件系统中的..
fn server_order(){} |
2.3 pub struct
和pub enum
pub放在struct前,struct变为公共的,但是struct的字段还是默认私有的;struct的字段需要单独设置pub
来变成共有的。
mod back_of_house |
pub放在enum前,enum是公共的,里面的变体也是公共的。
3. use
关键字
可以使用use
关键字将路径导入作用域中,仍然遵循私有性规则。
相对路径、绝对路径都可以
mod front_of_house |
3.1 use的习惯用法
-
函数:针对函数一般引入其父模块,防止函数重名情况(父级)
-
struct,enum:指定完整路径(本身)
use std::collections::HashMap;//结构体
fn main()
{
let mut map = HashMap::new();
map.insert(1,2);
} -
同名条目:父级,比如两个定义在不同模块的同名struct,要指定到父级
use std::fmt;
use std::io;
fn f1() -> fmt::Result{}
fn f2()-> io::Result{}
fn main(){}也可以使用
as
关键字,为引入的路径指定本地的别名use std::fmt::Result;
use std::io::Result as IoResult;
fn f1() -> Result{}
fn f2()-> IoResult{}
fn main(){}
3.2 使用pub use
重新导入名称
使用use
将路径导入到作用域内后,该名称在此作用域内私有,pub use
重导出,将条目引入作用域,该条目可以被外部代码引入到它们的作用域
3.3 使用外部包(package)
cargo.toml添加依赖的包(package)
标准库(std)也被当做外部包,但是不需要修改cargo.toml添加,需要使用use将std中特定的条目引入当前作用域
3.4 使用嵌套路径清理大量的use语句
可以使用嵌套路径在同一行内将同一个包或模块下的多个条目进行引入
路径相同的部分::{路径差异的部分} |
use std::cmp::Ordering; |
3.5 通配符*
可以使用通配符*
将某个模块下的所有条目引入,但是要谨慎使用。使用场景:
- 测试,将所有被测试代码引入到tests模块
- 有时被用于预导入(prelude)模块
use std::collections::* |