Rust基础知识10 - Package、Crate、Module

简介

  • 接上回

Rust 的模块系统的基本概念

Package、Crate、Module、Path:

顶层、Package 包,Cargo的特性,让你构建、测试、共享crate
第二层、Crate 单元包,一个模块数,它可以产生一个library 或可执行文件。
第三层、Module 模块,控制代码的组织、作用域、私有路径。
最后、Path 路径,为struct、function或module等项命名的方式。

Crate 相关

  • 包(package)创建规则:
1、一个包中至多只能包含一个库Crate。
2、包中可以包含任意多个二进制Crate。
3、包中至少包含一个 crate,无论是库的还是二进制的。
4、包中应该包含一个 Cargo.toml 配置文件,用来说明如何去构建这些 crate。
  • Package 的特点:
1、包含一个 Cargo.toml
2、默认的项目的 `binary crate` 的入口文件是 src/main.rs 
3、默认的库 `library crate` 的入口文件是 src/lib.rs 库名称与Package的名称相同。
4、所以一个package 既可以包含一个 `main.rs` 也可以包含 一个 `lib.rs`
5、文件放置 src/bin 下面,每个文件都是单独的binary crate

s

定义Module 来控制作用域和私有性

  • Module 在一个crate内,将代码进行分组。
  • 增加可读性,易于复用。
  • 控制项目(item)的私有性,通过public、private
  • 通过 mod 关键字创建module
  • module 是可嵌套的。
  • module 可以包含其他项(struct、enum、常量、trait、函数等)的定义

代码测试

  • 举一个例子比上面的文字更有意义:
pub mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist () -> u32 {
            println!("############ add_to_waitlist ############");
            555
        }
    }
    mod serving {
        pub fn take_order (){
            
            println!("RUN take_order");
        }
        pub fn serve_order (){
            println!("RUN serve_order");
        }
    }
}

路径 Path

  • 为了在Rust 的模块中找到某个条目,需要使用路径。
  • 路径的两种形式:
1、绝对路径,从 crate root 开始,使用crate 名或者字面值crate 
2、相对路径,从当前模块开始,使用self,super 或者当前模块的标识符号。
  • 路径至少由一个标识符组成,标识符之间使用::

使用pub 关键字

  • 默认上 Rust 中所有条目(函数,方法,struct,enum,模块,常量)默认是私有的
  • 父级模块无法访问子模块中的私有条目。
  • 子模块里可以使用所有祖先模块中的条目。
  • pub 放在 struct 前,struct 是公共的,但是struct 的字段默认是私有的。
  • pub 放在 enum 前,enum 是公共的,里面枚举变体也都是公用的,这个比较特殊,要注意。

super 关键字

  • super 用来访问父级模块路径中的内容,类似文件系统中的..

use 关键字

  • use 是作用域引入关键字。
  • use 同样需要遵循私有性原则,实例代码如下:
fn main(){
    // 通过引用可以让代码更精炼。
    use hello::front_of_house::hosting;
    let num = hosting::add_to_waitlist();
    println!("AAA{}", num);
}
image.png

as 关键字

  • 别名关键字,举例
use hello::front_of_house::hosting as newhost;
fn main(){
    // 通过引用可以让代码更精炼。
    let num = newhost::add_to_waitlist();
    println!("AAA{}", num);
}

打包引用多个模块

  • 如果模块重复可以通过 { } 括号区块进行打包
use std::io;
use std::io::Write;
// 可以改成
use std::io:: { self, Write} ;

pub use 重新导出名称

  • 使用 use 将路径导入到作用域内后,该名称在此作用域内是私有的。
  • pub use 重导入可以将条目引入作用域,该条目就可以被外部代码引入到他们的作用域。

通配符 * 引入

  • 通配符 * 可以把路径中所有公共条目都引入到作用域中,但是要谨慎使用,一般在测试的时候才需要,或者被用于预导入时。

使用外部包

  • 在Cargo.toml 中添加依赖的包,之后运行 cargo build 时候程序会 crates.io 寻找依赖库。
  • 举例,修改 Cargo.toml
[package]
name = "hello"
version = "0.1.0"
authors = ["Kami1983 "]
edition = "2018"

# 添加依赖 
[dependencies]
rand = "0.8.3"
  • 外部包的使用同样需要use 关键字,例如:
use rand::Rng;

fn main() {
    // 生成一个0~9的的随机数,gen_range 根据Rust 版本不同参数写法上也是有区别的需要注意
    // 较新版本的是 gen_range(0,10)
    let randnum = rand::thread_rng().gen_range(0..10);
    println!("Rand num is :  {}", randnum);
}

如何将模块拆分到不同的文件

  • 拆分是降解负责度最好的办法没有之一,所以Rust 也可以将模块内容拆分到不同的文件中的,而且分厂简单。
  • Rust 会从与模块同名的文件中加载内容,但却可以让模块树的结构不发生变化。
  • 随着模块逐渐变大,该技术可以让你把模块的内容移动到其他文件中。
  • 举例,之前有一段代码如下:
mod testmod {
    pub fn say_words() {
        println!("Hello world!");
    }
}

fn main() { 
    testmod::say_words();
}
  • 突然间觉得代码过于臃肿,要将 testmod 单独放到其他的文件中就可以简单的改进一下:
# 原来的 main.rs
// 直接 mod 名字; 就可以将该模块分离,成 testmod.rs 文件
mod testmod ;
fn main() { 
    testmod::say_words();
}
------------------ 注意这里面的内容放到  testmod.rs 单独文件中
# 分离出来的 testmod.rs
pub fn say_words() {
    println!("Hello world!");
}
image.png
  • 运行之后效果相同

结束

  • 感谢阅读,这章节还是很有意思的,因为一个好的结构化代码,离不开项目工程结构的优化和解耦。

你可能感兴趣的:(Rust基础知识10 - Package、Crate、Module)