六、模块化

153 阅读3分钟

六、模块化

  • 模块系统
    • crate:一个模块的树形结构,它形成了库或二进制项目
    • 包:Packages,cargo 的一个功能,允许你构建、测试和分享 crate
    • 模块:允许你控制作用域和路径的私有性,可通过 use 来使用公有的包
    • 路径:一个命名,如结构体、函数、模块等项目的访问

1. crate 和 package

  • crate

    • 一个模块的树形结构,它形成了库或二进制项目
    • crate root 是一个源文件,Rust 编译的起点
  • (package)

    • 提供一系列功能的一个或多个 crate
    • 包含一个 Cargo.toml 文件
    • 至多只能包含一个库
    • 包含至少一个二进制 crate
  • Cargo 约定

    • src/main.rs 就是一个与包同名的二进制 crate 的根节点
    • 如果包目录中包含 src/lib.rs,则包带有与其同名的库 crate,且 src/lib.rs 是 crate 的根节点

2. Rust 模块

  • Rust 中,注册的一个 mod 块即为一个模块

  • Rust 中,如果一个文件没有指定 mod 块,则该文件的整个内容将被视为一个模块 (个人理解)

  • 特性

    • 允许命名一个 item 的路径,并通过 use 来引入一个指定的路径
    • 允许使用 pub 关键字来将 item 变为公有的
  • Rust 中,默认所有的 item 都是私有的

    • item 包括:函数、方法、结构体、枚举、(内部)模块、常量
  • 作用

    • 将一个 crate 的代码分组,提高代码的可读性与复用性
  • 引用模块及其成员

    • 使用关键字 use 来引用
    • 每一级的标识符之间,都以 :: 分割
    • 相对路径
      • 从当前模块开始,以 self 开头,访问当前目录及其子目录和模块
        • 类似于 JavaScript 中的 ./ 开头
      • 从当前模块开始,以 super 开头,访问当前目录的父级目录及其子目录和模块
        • 类似于 JavaScript 中的 ../ 开头
    • 绝对路径
      • 从 crate 开始,以 crate 名或者字面值 crate 开头,来访问对应的目录和模块
        • 类似于在 Typescript 中或有根目录别名解析的工具中,以 @/ 开头的访问
  • 模块的使用

    • 使用 pub 关键字暴露 item 的路径

    • 使用 use 关键字将 item 引入当前作用域

    • 使用 as 关键字将引入的 item 在当前作用域内重命名

    • 使用 pub use 重新导出 item

    • 在 Cargo.toml 文件的 [dependencies] 项下列出需要使用的外部包和对应的版本,就可以像引入项目内的 item 一样引入这个包的 item 了

    • 可通过嵌套路径消除大量相同路径的 use

    • 可通过 glob 运算符将某个模块内的所有 public 定义引入作用域

  • 示例代码

    • src/main.rs

      mod structure;
      use structure::student;
      use student::Gender as StudentGender;
      use student::{check_number, create_student};
      
      fn main() {
        student::struct_test();
        let gender = StudentGender::Girl;
        let name = String::from("Ale");
        let ale = create_student(name, 15, gender);
        ale.self_introduction();
      
        let num = 1;
        println!("{} is {}", num, check_number(num));
        let num2 = 0;
        println!("{} is {}", num2, check_number(num2));
      }
      
    • src/structure/mod.rs

      pub mod student;
      
      
    • src/structure/student.rs

      pub enum Gender {
        Boy,
        Girl,
      }
      
      pub struct Student {
        age: u16,
        name: String,
        class: u8,
        grade: u8,
        gender: Gender,
        student_number: String,
      }
      
      impl Student {
        pub fn self_introduction(&self) {
          let gender = get_gender(&self.gender);
          println!("Hello everyone, my name is {}.", &self.name);
          println!("I'm a {} years old {}.", &self.age, gender);
          println!("I'm in class {}, grade {}.", &self.class, &self.grade);
          println!("My student number is {}.", &self.student_number);
          println!("I'm very happy to join this big family!");
          println!();
        }
      }
      
      pub fn struct_test() {
        let jelly = create_student(String::from("Jelly"), 15, Gender::Girl);
        jelly.self_introduction();
        let cherry = Student {
          name: String::from("Cherry"),
          student_number: get_student_number(),
          gender: Gender::Boy,
          ..jelly
        };
        cherry.self_introduction();
      }
      
      pub fn create_student(name: String, age: u16, gender: Gender) -> Student {
        return Student {
          age,
          name,
          gender,
          class: 12,
          grade: 8,
          student_number: get_student_number(),
        };
      }
      
      fn get_student_number() -> String {
        return String::from("abc");
      }
      
      fn get_gender(gender: &Gender) -> String {
        match gender {
          Gender::Boy => String::from("boy"),
          Gender::Girl => String::from("girl"),
        }
      }