rust(七)- package,crate,module

318 阅读4分钟

package、crate、定义moudule

  • rust的代码组织
    • 代码组织主要包括
      • 哪些细节可以暴露,哪些细节是私有的
      • 作用域内哪些名称有效
    • 模块系统
      • package(包):cargo的特性,让你构建、测试、共享crate
      • crate(单元包):一个模块树,它可产生一个libraty或可执行文件
      • module(模块)、use:让你控制代码的组织、作用域、私有路径
      • path(路径):为struct、Function、module等项命名的方式
  • pacakge 和 Crate
    • crate的类型:
      • binary
      • library
    • crate root:
      • 是源代码文件
      • rust编译器从这里开始,组成你的crate的根module
    • 一个package:
      • 包含1个cargo.toml,它描述了如何构建这些crates
      • 只能包含0-1个library crate
      • 可以包含任意数量的binary crate
      • 但必须至少包含一个crate(libraty 或 binary)
  • cargo的惯例
    • src/main.rs:
      • binary crate 的 crate tool
      • crate名与package名相同
    • src/lib.rs:
      • package包含一个library crate
      • library crate 的 crate tool
      • crate名与package名相同
    • cargo 把 crate root 文件交给rustc来构建library或binary
    • 一个package可以同时包含src/main.rs和src/lib.rs
      • 一个binary crate,一个library crate
      • 名称与package名相同
    • 一个package可以有多个binary crate:
      • 文件放在src/bin
      • 每个文件是单独的binary crate
  • crate的作用
    • 将相关功能组合到一个作用域内,便于在项目间进行共享
      • 防止冲突
    • 例如 rand crate,访问它的功能需要通过它的名字:rand
  • 定义moudule来控制作用域和私有性
    • module
      • 在一个crate内,将代码进行分组
      • 增加可读性,易于复用
      • 控制项目的私有性。public、private
    • 建立module:
      • mod关键字
      • 可嵌套
      • 可包含其它项(struct、enum、常量、trait、函数等)的定义
  • module
    • src/main.rs和src/lib.rs叫做crate roots:
      • 这两个文件(任意一个)的内容形成了名为crate的模块,位于整个模块树的根部
    backyard
     ├── Cargo.lock
     ├── Cargo.toml
     └── src
         ├── garden
         │   └── vegetables.rs
         ├── garden.rs
         └── main.rs
    
    

路径path

  • 为了在rust的模块中找到某个条目,需要使用路径。
  • 路径的两种形式
    • 绝对路径: 从crate root开始,使用crate名或字面值crate
    • 相对路径:从当前模块开始,使用self,super或当前模块的标识符
  • 路径至少由一个标识符组成,标识符之间全用::.
mod front_of_house {
       mod hosting {
           fn add_to_waitlist() {}
       }
   }

   pub fn eat_at_restaurant() {
       // Absolute path
       crate::front_of_house::hosting::add_to_waitlist();

       // Relative path
       front_of_house::hosting::add_to_waitlist();
   }
  • 私有边界
    • 模块不仅可以组织代码,还可以定义私有边界
    • 如果想把函数或struct等设为私有,可以将它放到某个模块中
    • Rust 中所有的条目(函数、方法、struct、enum、模块、常量)默认是私有的
    • 父级模块无法访问子模块的私有条目
    • 子模块里可以使用所有祖先模块中的条目
  • pub 关键字
    • 使用pub关键字来将某些条目标记为公共的
  • super关键字
    • 上一级路径
    fn deliver_order() {}
    
     mod back_of_house {
         fn fix_incorrect_order() {
             cook_order();
             super::deliver_order();
         }
    
         fn cook_order() {}
     }
    
    
  • pub stuct
    • pub放在struct前:
      • struct是公共的
      • struct的字段默认是私有的
    • struct的字段需要单独设置pub来变成共有
  • pub enum
    • pub放在enum前:
      • enum是公共的
      • enum的变体也都是公共的
  • use关键字
    • 可以使用use关键字将路径导入到作用域内
      • 仍遵循私有性规则
      • 使用use来指定相对路径
      mod front_of_house {
             pub mod hosting {
                 pub fn add_to_waitlist() {}
             }
         }
      
         pub use crate::front_of_house::hosting;
      
         pub fn eat_at_restaurant() {
             hosting::add_to_waitlist();
         }
      
    • use的习惯用法
      • 函数:将函数的父级模块引入作用域(指定到父级)
      • struct,enum,其它:指定完整路径(指定到本身)
      • 同名条目:指定到父级
  • 使用pub use 重新导出名称
    • 使用use将路径(名称)导入到作用域内后,该名称在此作用域内是私有的
    • pub use:重导出
      • 将条目引入作用域
      • 该条目可以被外部代码引入到它们的作用域
  • 使用外部包
    • cargo.toml添加依赖包(package)
    • use 将特定条目引入作用域
    • 标准库(std)也被当作外部包
      • 不需要修改 cargo.toml来包含std
      • 需要使用use将std中的特定条目引入当前作用域
     cd ~/.cargo
     touch config
     
    

image.png

  • 使用嵌套路径清理大量的use语句
    • 如果使用同一个包或模块下的多个条目(例子)
    • 可使用嵌套路径在同一行内将上述条目进行引入:
      • 路径相同的部分::{路径差异的部分}
      • 如果两个use路径之一是另一个的子路径
        • 使用self
        use rand::Rng;
          // --snip--
          use std::{cmp::Ordering, io};
          // --snip--
        
          fn main() {
              println!("Guess the number!");
        
              let secret_number = rand::thread_rng().gen_range(1..101);
        
              println!("The secret number is: {}", secret_number);
        
              println!("Please input your guess.");
        
              let mut guess = String::new();
        
              io::stdin()
                  .read_line(&mut guess)
                  .expect("Failed to read line");
        
              let guess: u32 = guess.trim().parse().expect("Please type a number!");
        
              println!("You guessed: {}", guess);
        
              match guess.cmp(&secret_number) {
                  Ordering::Less => println!("Too small!"),
                  Ordering::Greater => println!("Too big!"),
                  Ordering::Equal => println!("You win!"),
              }
          }
        
  • 通配符 *
    
     #![allow(unused)]
     fn main() {
     use std::collections::*;
     }
    
    

将模块内容称动到其它文件

  • 将模块内容移动到其它文件
    • 模块定义时,如果模块名后边是“;”,而不是代码块:
      • rust会从与模块同名的文件中加载内容
      • 模块树的结构不会变化
    • 随着模块逐渐变大,该技术让你可以把模块的内容移动到其它文件中
mod front_of_house;

pub use crate::front_of_house::hosting;

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