Skip to content

模块 Crate

模块

Rust 中的模块(modules)是用来组织和管理代码的机制。一个模块可以包含函数、结构体、枚举、traits 等。

在 Rust 中,模块使用 mod 关键字来定义,并且可以嵌套。一个模块可以在一个文件中定义,或者分布在多个文件中。

下面是一个简单的例子来说明模块的使用:

mod my_module {
    fn private_function() {
        println!("This is a private function");
    }

    pub fn public_function() {
        println!("This is a public function");
    }

    pub mod nested_module {
        pub fn nested_function() {
            println!("This is a nested function");
        }
    }
}

fn main() {
    my_module::public_function();

    // 无法直接调用 private_function,因为它是私有的
    // my_module::private_function();

    my_module::nested_module::nested_function();
}

在上面的例子中,my_module 是一个模块,它包含了一个私有函数 private_function 和一个公共函数 public_functionmy_module 模块中还定义了一个嵌套模块 nested_module,它包含了一个公共函数 nested_function

main 函数中,我们可以通过 my_module::public_function() 直接调用 public_function。但是,我们无法直接调用 private_function,因为它是私有的。我们可以通过 my_module::nested_module::nested_function() 调用 nested_function

use crate::my_mod::{publ,message};

mod my_mod {
    fn pri(a:i32,b:i32) -> i32 {
       return a + b; 
    }

    pub fn publ(a:i32,b:i32) ->i32 {
        let temp = a * pri(a, b);
        return temp;
    }

    pub struct message {
        pub mess:String,
    }

    impl message {
        pub fn say(&self) {
            println!("{}",self.mess);
        }
    }
}

fn main() {
    println!("ans is {}",publ(3, 4));
    let m = message {
        mess:"Hello".to_string(),
    };
    m.say();
}

use xxxx as yyyy ; 类似于Python中的import xxxx as yyyy

模块、路径、use关键词和pub关键词如何在编译器中工作

  • 从 crate 根节点开始: 当编译一个 crate, 编译器首先在 crate 根文件(通常,对于一个库 crate 而言是_src/lib.rs_,对于一个二进制 crate 而言是_src/main.rs_)中寻找需要被编译的代码。
  • 声明模块: 在 crate 根文件中,你可以声明一个新模块;比如,你用mod garden声明了一个叫做garden的模块。编译器会在下列路径中寻找模块代码:
    • 内联,在大括号中,当mod garden后方不是一个分号而是一个大括号
    • 在文件 src/garden.rs
    • 在文件 src/garden/mod.rs
  • 声明子模块: 在除了 crate 根节点以外的其他文件中,你可以定义子模块。比如,你可能在_src/garden.rs_中定义了mod vegetables;。编译器会在以父模块命名的目录中寻找子模块代码:
    • 内联,在大括号中,当mod vegetables后方不是一个分号而是一个大括号
    • 在文件 src/garden/vegetables.rs
    • 在文件 src/garden/vegetables/mod.rs
  • 模块中的代码路径: 一旦一个模块是你 crate 的一部分,你可以在隐私规则允许的前提下,从同一个 crate 内的任意地方,通过代码路径引用该模块的代码。举例而言,一个 garden vegetables 模块下的Asparagus类型可以在crate::garden::vegetables::Asparagus被找到。
  • 私有 vs 公用: 一个模块里的代码默认对其父模块私有。为了使一个模块公用,应当在声明时使用pub mod替代mod。为了使一个公用模块内部的成员公用,应当在声明前使用pub
  • use 关键字: 在一个作用域内,use关键字创建了一个成员的快捷方式,用来减少长路径的重复。在任何可以引用crate::garden::vegetables::Asparagus的作用域,你可以通过 use crate::garden::vegetables::Asparagus;创建一个快捷方式,然后你就可以在作用域中只写Asparagus来使用该类型。

文件结构:

$ tree .
.
├── my
│   ├── inaccessible.rs
│   └── nested.rs
├── my.rs
└── split.rs

In split.rs:

// This declaration will look for a file named `my.rs` and will
// insert its contents inside a module named `my` under this scope
mod my;

fn function() {
    println!("called `function()`");
}

fn main() {
    my::function();

    function();

    my::indirect_access();

    my::nested::function();
}

In my.rs:

// Similarly `mod inaccessible` and `mod nested` will locate the `nested.rs`
// and `inaccessible.rs` files and insert them here under their respective
// modules
mod inaccessible;
pub mod nested;

pub fn function() {
    println!("called `my::function()`");
}

fn private_function() {
    println!("called `my::private_function()`");
}

pub fn indirect_access() {
    print!("called `my::indirect_access()`, that\n> ");

    private_function();
}

In my/nested.rs:

pub fn function() {
    println!("called `my::nested::function()`");
}

#[allow(dead_code)]
fn private_function() {
    println!("called `my::nested::private_function()`");
}

In my/inaccessible.rs:

#[allow(dead_code)]
pub fn public_function() {
    println!("called `my::inaccessible::public_function()`");
}

Let's check that things still work as before:

$ rustc split.rs && ./split
called `my::function()`
called `function()`
called `my::indirect_access()`, that
> called `my::private_function()`
called `my::nested::function()`

File hierarchy - Rust By Example

我们可以通过在路径的开头使用 super ,从父模块开始构建相对路径,而不是从当前模块或者 crate 根开始。这类似以 .. 语法开始一个文件系统路径。