Skip to content

package 和 crate

  • package(包): Cargo 的特性, 可构建/测试/共享 crate
  • crate(单元包): 一个模块树, 可产生一个 libary 或 binary
  • module/use(模块): 控制代码的组织方式, 作用域, 私有路径

crate 类型

  • binary
  • libary

Crate Root

  • 源代码文件入口
  • Rust 编译器从这里开始, 组织 Crate 的根 Module

Package

  • 包含一个 Cargo.toml 描述了如何构建这些 crates
  • 只能包含 0-1 个 libary crate
  • 可以宝航任意数量的 binary crate
  • 但是至少要包含一个 crate(libary 或 binary)

Cargo crate Root的惯例

Cargo 把 crate root 文件交给 rustc 来构建 libary 或 binary

  • 一个 package 可以同时包含 src/main.rssrc/lib.src, 一个是 binary crate 的入口文件(root), 一个是 libary crate 的入口文件(root)

  • 一个 package 可以有多个 binary crate, 文件放在 src/bin, 每个文件都是单独的 crate

src/main.rs

  • binary crate 的 crate root
  • crate 名与 package 名相同

src/lib.rs

  • package 包含一个 libary crate
  • libary crate 的 crate root
  • crate 名与 package 名相同

crate 的作用

  • 将相关的功能组合到一个作用域内, 便于在项目之间进行共享
  • 防止命名冲突
  • 例如生成随机数的 rand 就是一个 crate, 访问他需要通过他的 package 名 rand

定义 module

  • 将代码分组, 易于管理代码
  • 增加可维护性, 易于复用
  • 控制项目(item)的私有性, public private 等
  • module 是可嵌套的
  • 模块默认是私有的, 如果要外部可以使用就需要使用 pub 关键字

1.创建 cargo 项目

sh
# 注意名字,后续再使用绝对路径的时候会用到
cargo new modsys;

2.创建 libary root

创建模块的入口文件: src/lib.rs

rs
pub mod math {
    pub mod rand {
        pub fn random() {
            println!("取随机数");
        }
        pub fn range() {
            println!("在范围中取随机数");
        }
    }
    pub mod take_integer {
        pub fn ceil() {
            println!("向上取整");
        }
        pub fn call_anthor_mod_fn() {
            // 通过模块路径调用其他模块的方法
            crate::math::rand::random();
            println!("测试调用其他模块");
        }

        // 模块和方法, 默认是私有的, 如果不加 pub 关键字
        // 在外部无法使用, 只能在这个文件中使用
        // 可能会让编译器报警告: function `floor` is never used
        fn floor() {
            println!("向下取整");
        }
    }
}

3.使用 libary

rs
// 使用 use 关键字导入模块
// 不能导入私有模块/方法, 如 floor 方法
use modsys::math::rand;              // 1.导入整个模块
use modsys::math::take_intger::ceil; // 2.导入模块下具体方法
use modsys::math::take_intger::call_anthor_mod_fn;

// 上面这样的方式有些太麻烦了
// 使用 {} 可以一次导入多个模块或具体方法
// use modsys::math::{rand, take_intger};
// use modsys::math::rand::{random, range};

// 使用 * 可以一次导入全部模块/方法
// use modsys::math::*;
// use modsys::math::rand::*;

fn main() {
    rand::random();
    rand::range();
    ceil();
    call_anthor_mod_fn();
}

4. 使用 as 关键字解决重名问题

rust
// 假设有两个这样的模块, 都有 read 方法
// 那么使用 as 关键字就可以解决问题
use fs::read as readFile;
use buffer::read as readBuffer;

fn main() {
  // 这样使用即可, 不会命名冲突
  readFile();
  readBuffer();
}

将模块拆分为多个文件(推荐)

上面代码介绍了如何定义和使用模块, 但是问题是, 所有模块都在一个文件中 src/lib.rs

这其实是不太合理的, 如果一个模块文件内容比较多, 全部放到一个文件中, 就会导致这个文件特别大, 难以维护

既然已经学会了如何定义和使用模块, 那就直接上代码

文件目录结构

txt
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── lib.rs
    ├── main.rs
    └── math
        ├── rand.rs
        └── take_integer.rs

文件内容

rs
// 导入并使用其他模块
use modsys::math::rand;
use modsys::math::take_integer::*;

fn main() {
    rand::random();
    rand::range();
    ceil();
    floor();
    call_anthor_mod_fn();
}
rs
// 只定义了模块, 但是并没有具体实现
// 注意模块路径和要和文件路径一致
// math         -> src/math
// rand         -> src/math/rand
// take_integer -> src/math/integer
pub mod math {
  pub mod rand;
  pub mod take_integer;
}
rs
pub fn random() {
    println!("取随机数");
}

pub fn range() {
    println!("在范围中取随机数");
}
rs
// 在一个模块中使用另外一个模块的功能
use crate::math::rand::random;

pub fn ceil() {
    println!("向上取整");
}

pub fn floor() {
    println!("向下取整");
}

pub fn call_anthor_mod_fn() {
    random();
    println!("导入测试其他模块的方法");
}

使用 pub use 关键字调整导出结构

上面的例子可以看到, 虽然说, 这样规划mod在开发时是比较合理的, 但是在使用的时候就比较费劲, 可否在 ./lib.rs 中直接导出方法, 导入是直接忽略这些模块

rust
// 导入并使用其他模块
// use modsys::math::rand;
// use modsys::math::take_integer::*;

// 直接导入
use modsys::{ rand, take_integer, call_anthor_mod_fn };

fn main() {
    rand::random();

    rand::random();
    rand::range();
    take_integer::ceil();
    take_integer::floor();
    call_anthor_mod_fn();
}
rust
// 只定义了模块, 但是并没有具体实现
// 注意模块路径和要和文件路径一致
// math         -> src/math
// rand         -> src/math/rand
// take_integer -> src/math/integer

// 重新导出模块(让导入的时候可以不用按照文件路径)
pub use crate::math::rand;
pub use crate::math::take_integer;
pub use crate::math::take_integer::call_anthor_mod_fn;

pub mod math {
  pub mod rand;
  pub mod take_integer;
}

Released under the MIT License.