模块定义

mod

模块 让我们可以将一个crate中的代码进行分组,以提高可读性与重用性。模块还可以控制项的 私有性,即项是可以被外部代码使用的(public,还是作为一个内部实现的内容,不能被外部代码使用(private

模块定义

模块通过关键字mod加模块定义,例如:

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

文件src/main.rssrc/lib.rs,对应的模块是crate,(crate)的模块结构(module structure),也叫做模块树(module tree):

crate
 └── front_of_house
     ├── hosting
        ├── add_to_waitlist
        └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

模块crate默认存在,不需要通过关键字mod方式来定义。与文件系统类似,文件系统的根节点是/,(crate)的根节点是crate.

  • 绝对路径,从箱(crate)的根节点开始,(crate)的名称,crate
  • 相对路径,从当前模块开始,可以使用self, super
// 文件内绝对路径 Absolute path
crate::front_of_house::hosting::add_to_waitlist();

// 相对路径 Relative path
front_of_house::hosting::add_to_waitlist();

同文件模块

相关代码和数据被分组到一个模块中并存储在同一文件中。

fn main() {
   greetings::hello();
}

mod greetings {
  // ⭐️ By default, everything inside a module is private
  pub fn hello() { // ⭐️ So function has to be public to access from outside
    println!("Hello, world!");
  }
}

模块也可以嵌套。

fn main() {
  phrases::greetings::hello();
}

mod phrases {
  pub mod greetings {
    pub fn hello() {
      println!("Hello, world!");
    }
  }
}

self关键字用于引用相同的模块,而super关键字用于引用父模块。还可以使用super关键字从模块内部访问根函数。

fn main() {
  greetings::hello();
}

fn hello() {
  println!("Hello, world!");
}

mod greetings {
  pub fn hello() {
    super::hello();
  }
}

编写测试时,最好在测试模块中编写测试,因为它们仅在运行测试时才编译。

fn greet() -> String {
    "Hello, world!".to_string()
}

#[cfg(test)] // only compiles when running tests
mod tests {
    use super::greet; // import root greet function

    #[test]
    fn test_greet() {
        assert_eq!("Hello, world!", greet());
    }
}

模块可见性

  • 所有元素,函数functions,方法methods,结构体structs,枚举enum,模块modules,常量constants,默认是私有的,对外公开(public),需要通过关键字pub声明
    • 即便是共有的结构体(public structs),内部的元素(fields)和方法(methods)仍是私有的(private)
    • 共有的枚举(public enums),其所有变天(variants)也同为共有(public)
  • 父模块中的元素,不能使用子模块中的私有元素
  • 子模块中的元素,可以使用父模块的元素

譬如将制作一个名为print_thingsmod,它具有一些与打印相关的功能。

mod print_things {
    use std::fmt::Display;

    fn prints_one_thing<T: Display>(input: T) { // Print anything that implements Display
        println!("{}", input)
    }
}

fn main() {}

可以看到我们在print_things里面写了std::fmt::Display;,因为它是一个单独的空间。如果您在main()中使用std::fmt::Display;编写,将无济于事。同样,我们现在不能从main()调用它。如果在fn前面没有pub关键字,它将保持私有状态。让我们尝试在没有发布的情况下调用它。这是一种编写方式:

// 🚧
fn main() {
    crate::print_things::prints_one_thing(6);
}

crate 意味着在该文件中。里面是mod print_things,最后是prints_one_thing()函数。您可以每次编写该代码,也可以编写用于导入的用法。现在,我们可以看到错误提示它是私有的:

// ⚠️
mod print_things {
    use std::fmt::Display;

    fn prints_one_thing<T: Display>(input: T) {
        println!("{}", input)
    }
}

fn main() {
    use crate::print_things::prints_one_thing;

    prints_one_thing(6);
    prints_one_thing("Trying to print a string...".to_string());
}

error[E0603]: function `prints_one_thing` is private
  --> src\main.rs:10:30
   |
10 |     use crate::print_things::prints_one_thing;
   |                              ^^^^^^^^^^^^^^^^ private function
   |
note: the function `prints_one_thing` is defined here
  --> src\main.rs:4:5
   |
4  |     fn prints_one_thing<T: Display>(input: T) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

很容易理解函数print_one_thing是私有的。它还显示了在哪里可以找到该函数。这是因为一旦开始使用mod,您可能还会使用多个文件,并且很难找到内容。现在我们只写pub fn而不是fn,一切正常。

mod print_things {
    use std::fmt::Display;

    pub fn prints_one_thing<T: Display>(input: T) {
        println!("{}", input)
    }
}

fn main() {
    use crate::print_things::prints_one_thing;

    prints_one_thing(6);
    prints_one_thing("Trying to print a string...".to_string());
}

6
Trying to print a string...
上一页
下一页