系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目

前言

本章节主要将使用包(Packages)、单元包(Crates)和模块(Module)来管理项目。

主要教材参考 《The Rust Programming Language》


一、Rust的模块系统

1.1、Rust的模块系统

Rust 组织主要包括:

  • 哪些细节可以暴露,哪些细节是私有的;
  • 作用域内哪些名称有效

Rust 模块系统主要包含:

  • Package(包):Cargo 的特性,让你构建、测试、共享 crate;
  • Crate(单元包):一个模块树,它可产生一个library或可执行文件
  • Module(模块):use:让你控制代码的组织、作用域、私有路径
  • Path(路径):为 struct、function 或 module 等项命名的方式;

二、包(Package)和单元包(Crate)

2.1、包(Package)

  • 一个包含有一个 Cargo.toml,它描述了如何构建这些 Crates;
  • 只能包含 0-1 个 library crate;
  • 可以包含任意数量的 binary crate;
  • 但必须至少包含一个 crate (library/binary)

2.2、单元包(Crate)

2.2.1、Crate 的类型

Crate 有两种类型

  • binary crate:使用 cargo new 默认创建的是 binary crate;
  • library crate:使用cargo new --lib 创建 library crate;

2.2.3、Crate Root

2.2.3.1、Crate Root
  • 是源代码文件(src/main. rs)
  • Rust 编译器从这里开始,组成你的 Crate 的根 Module。
2.2.3.2、Cargo 惯例

src/main.rs:

  • binary crate 的 Crate Root
  • crate 名与 package 名相同

src/lib.rs:

  • package 包含一个 library crate
  • library crate 的 Crate root

Cargo 会把 crate root 文件交给 rustc 来构建 library 或 binary。

2.2.4、Crate 的作用

  • 将功能相关组合成一个作用域内,便于在项目之间进行共享:防止冲突
  • 例如 rand crate ,访问它的功能需要通过它的名字:rand

2.3、使用外部包(package)

2.3.1、使用外部包(package)

在 cargo.toml 添加依赖的包(package),会从 https://crates.io/ 网站下载依赖。

[package]
name = "flappy"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bracket-lib = "~0.8"

2.3.2、 cargo 源修改

vi ~/.cargo/config


[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
# 指定镜像tuna sjtu ustc rustcc
replace-with = 'tuna' 
 
# 中国科学技术大学
[source.ustc]
registry = "https://mirrors.ustc.edu.cn/crates.io-index"
# registry = "git://mirrors.ustc.edu.cn/crates.io-index"
 
# 上海交通大学
[source.sjtu]
registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index/"
 
# 清华大学
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
 
# rustcc社区
[source.rustcc]
registry = "git://crates.rustcc.cn/crates.io-index"

2.3.3、使用嵌套路径

//use std::io;
//use std::io::Write;

use std::io::{self, Write};

2.3.4、通配符 *

use std::collections::*;

一般用于测试场景,将所有被测试代码引入到 tests 模块;

三、定义 module 来控制作用域和私有性

3.1、module

  • 在一个crate 内,将代码进行分组
  • 增加可读性,易于复用
  • 控制项目(item) 的私有性,public、private

3.2、建立 module

  • mod 关键字
  • 可以嵌套
  • 可包含其它项(struct、enum、常量、trait、函数等)的定义

3.3、定义 module

mod front_of _house{
    mod hosting {
        fn add_to_waitlist(){}
        fn seat_at_table(){}
    }

    mod serving{
        fn tabke_order(){}
        fn server_order(){}
        fn take_payment(){}
    }
}

3.4、私有边界(privacy boundary)

  • 模块不仅可以组织代码,还可以定义私有边界
  • 如果想把函数或struct等设为私有,可以将它放到某个模块中;
  • Rust 中所有的条目(函数、方法、结构、枚举、模块、常量) 默认都是私有的;
  • 父模块无法访问子模块的私有条目
  • 子模块可以使用所有祖先模块中的条目

3.4、pub 关键字

使用 pub 关键字 可以 使得某些条目变成公共的;

pub struct:

  • struct 是公共的;
  • struct 的字段默认是私有的;

四、路径(Path)

4.1、路径(Path)

为了在 Rust 模块中找到某个条目,需要使用路径。路径的两种形式如下:

  • 相对路径:从当前模块开始,使用 self、super 或当前模块的标识符;
  • 绝对路径:从 crate root 开始,使用 crate 名 或 字面值 crate;

路径至少有一个标识符,标识符之间使用::分隔;

mod front_of_house{
    pub mod hosting {
        pub fn add_to_waitlist(){}
    }
}

pub fn eat_at_restaurant(){
    crate::front_of_house::hosting::add_to_waitlist();
    front_of_house::hosting::add_to_waitlist();
}

4.2、super 关键字

使用 super 关键字可以访问父级模块路径的内容



mod front_of_house{
    fn test(){

    }
    pub mod hosting {
        pub fn add_to_waitlist(){
            super::test();
        }
    }
}

pub fn eat_at_restaurant(){
    crate::front_of_house::hosting::add_to_waitlist();
    front_of_house::hosting::add_to_waitlist();
}

4.3、use 关键字

可以使用 use 关键字将路径导入到作用域内:仍然遵守私有性规则

use std::collections::HashMap;

fn main() {
    let mut map:HashMap<String, String>= HashMap::new();
    map.insert(String::from("key"), String::from("value"));
}

4.4、as 关键字

使用 as 关键字可以为引入的模块或struct等 起一个本地的别名

use std::fmt::Result as MyResult;

4.5、pub use

使用 pub use 重新导出名称,使用 use 将路径(名称)导入到作用域内后,该名称在此作用域内是私有的。

五、将模块移动到其它文件

模块定义时候,如果模块名后边是;,而不是代码块

  • Rust 会从与模块同名的文件中夹在内容;
  • 模块树的结构不会变化

总结

以上就是今天要讲的内容

  • 讲解包、单元包、模块的使用
Logo

欢迎加入我们的广州开发者社区,与优秀的开发者共同成长!

更多推荐