13_rust的模块系统,Package、Crate,定义Module,路径(Path)

rust的模块系统

代码组织包括:哪些细节对外暴露,哪些细节私有,作用域哪些名称有效等。
rust的模块系统:

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

pacakge和Crate

Crate的类型:binary、library。
Crate Root:源代码文件,rust编译器的开始之处,组成crate的根module。
一个Package

  • 包含1个Cargo.toml,描述了如何构建Crates(可能多个crate)。
  • 只能包含0-1个library crate。
  • 可包含任意数量的binary crate。
  • 但必须至少包含一个crate(library或binary)。
    可通过命令行创建一个Package:
$ cargo new test_prj
    Created binary (application) "test_prj" package
cd test_prj
code . # 使用vs code打开

可看到有配置文件Cargo.toml和源文件src/main.rs,但配置文件里并未提到main.rs文件,这是因Cargo惯例,默认是binary.crate的crate root。

Cargo的惯例

src/main.rs:

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

src/lib.rs

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

如果有main.rs就说明有一个binary crate,如果有lib.rs则说明有一个library crate。Carge把crate root文件交给rustc来构建library或binary。
1)一个Package可同时包含src/main.rs和src/lib.rs

  • 一个binary crate、一个library crate,名称都与package名相同
    2)一个Package可有多个binary crate
  • 文件放在src/bin下
  • 每个文件是单独的binary crate

crate的作用是将相关功能组合到一个作用域内,便于项目间进行共享以防止冲突,如rand crate,访问其功能需要通过rand名称来访问。

定义module

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

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

建立module:

  • mod关键字
  • 可嵌套
  • 可含其它项(struct、enum、常量、trait、函数等)的定义
mod high_modu { // 父moduler,顶层Moduler
    mod test1 { // 子moduler 1
        fn test_func() {}
        fn test_2() {}
    }
    mod test2 { // 子moduler 2
        fn test3() {}
    }
}

src/main.rs和src/lib.rs叫做crate.root,这两个文件(任意一个)的内容形成了名为crate的模块,位于整个模块树的根部。

crate
|- high_modu
   |- test1
      |- ...
   |- test2
      |- ...

路径(Path)

要找到模块里的内容,必须知道路径才行,与文件系统里的概念类似。
1)为了在rust的模块中找到某个条目,需要使用路径。
2)路径有两种形式:

  • 绝对路径:从crate root开始,使用crate名或字面值crate。
  • 相对路径:从当前模块开始,使用self(自身)、super(上一级)或当前模块的标识符

3)路径至少由一个标识符组成,标识符之间使用::符号
如:在一项目中创建一个src/lib.rs,内容如下:

mod test_modu1 { // lib.rs的内容隐式组成了名为crate的模块,所以绝对路径就从crate开始。
    mod test_modu2 {
        fn add_num() {}
    }
}
pub fn test_func() { // 测试调用test_modu2里的函数,与test_modu1在同一个crate里。
    crate::test_modu1::test_modu2::add_num(); // 绝对路径调用,从crate开始
    test_modu1::test_modu2::add_num(); // 使用相对路径调用Moduler内函数,因为在同一个crate里,与test_modu1同级
}

私有边界(private boundary)

模块不仅可组织代码,还可定义私有边界,如果项把函数或struct等设为私有,可将其放在某个模块中。
rust中所有条目(函数、方法、struct、enum、模块、常量)默认是私有的
另外:(类似于作用域的概念)

  • 父级模块无法访问子模块中的私有条目
  • 子模块里可使用所有祖先模块中的条目
    使用pub关键字来将某些条目标记为公共的。
    上面的例子需要做如下修改
mod test_modu1 { // 因为在同一文件,都属于根节点,类似与同文件内的函数,可被同级调用
    pub mod test_modu2 { // 加pub关键字后才能被外部调用
        pub fn add_num() {}
    }
}
pub fn test_func() { // 测试调用test_modu2里的函数
    crate::test_modu1::test_modu2::add_num();
    test_modu1::test_modu2::add_num();
}

super关键字

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

fn test_super() {}
mod modu1 {
    fn test1() {
        test2();
        super::test_super();
        crate::test_super();
    }
    fn test2() {}
}

pub struct

在struct关键字前加pub关键字,struct为公共的,但struc的字段默认还是私有的。struct的字段需要单独设pub才会是公共的。

mod modu1 {
    pub struct st1 {
        pub str1: String, // 公共
        num1: i32, // 私有
    }
    impl st1 {
        pub fn test_func(str2: &str) { // 定义一关联函数
            st1 { // 返回值是st1的实例
                str1: String::from(str2),
                num1: 5,
            }
        }
    }
}
pub fn test_func2() {
    let mut st1_obj = modu1::st1::test_func("test1");
    st1_obj.st1 = String::from("test2"); // 可修改,因为是公共的
    st1_obj.num1 = 9; // 编译报错,不可访问私有字段
}

pub enum

定义与struct一样,在enum前加pub关键字,但加了之后,enum本身是公共的,enum的变体也都是公共的
因为enum的定义目的就是使用其内的枚举,如果不是公共的也就没意义了,不像struct常需要有私有字段。

posted @ 2023-10-22 00:09  00lab  阅读(135)  评论(0编辑  收藏  举报