rust组织结构

一 、crate

crate称为箱。

crate有两种形式:二进制箱(binary crate)和库箱(library crate)。

二进制箱必须有一个 main 函数,可以编译为可执行程序。

库箱并没有 main 函数,它们也不会编译为可执行程序,它们只是提供一些函数供其他项目使用。

crate root叫箱的根,是一个源文件,Rust编译器以它为起始点,构建你的crate。

二、package

package称为包。包就是一个工程项目,包必须有一个Cargo.toml文件。

一个包至少包含一个箱,这些箱最多包含一个库箱,但可以包含任意数量的二进制箱。

使用cargo new命令创建包。包名就是目录名。

如果使用cargo new proj创建包,src目录下会默认生成一个main.rs源文件。

如果使用cargo new --lib proj命令创建包,src目录下会默认生成一个lib.rs源文件。

Cargo约定:

src/main.rs是一个二进制箱的根。此箱名与包名相同。

src/lib.rs是一个库箱的根。此箱名与包名相同。

如果包只有src/main.rs文件,意味着包只含有一个二进制箱。此箱名与包名相同。

如果一个包同时含有 src/main.rs和src/lib.rs,则它包含两个箱:一个二进制箱和一个库箱,且名字都与包相同。

通过将文件放在src/bin目录下,一个包可以拥有多个二进制箱:src/bin下的每个文件都会编译成一个独立的二进制箱。此目录下的箱名与包名不同,而是与文件名相同。

三、模块

rust模块就是命名空间。

(一)声明模块

使用mod关键字来声明模块。

mod hello {
     pub fn say_hello() {
         println!("hello world");
     }
}

模块内的项默认是private,外部不可见,如果要外部可见需要加pub

模块可以嵌套,形成模块树(module tree)

mod nation {
     mod government {
         fn govern() {}
     }
     mod congress {
         fn legislate() {}
     }
     mod court {
         fn judicial() {}
     }
}

每个箱都是一个模块树。src/main.rs 和 src/lib.rs 叫做箱根,是因为这两个文件为模块树创建了一个名为 crate 的根模块。

crate
└──nation
         ├──government
         │     └──govern
         ├──congress
         │     └──legislate
         └──court
                 └──judicial

(二)使用模块

1.模块的路径

如何在模块树中找到一个项的位置,我们使用路径,就像在文件系统使用路径一样。为了调用一个函数,我们需要知道它的路径。

路径有两种形式:

绝对路径(absolute path)是以箱根开头的全路径:引用外部箱代码,是以箱名开头的绝对路径;引用当前箱代码,则以crate开头。

相对路径(relative path)从当前所在模块开始,以 self、super 或当前模块的标识符开头。

(1)路径以双冒号(::)为分割符

例如:

mod front_of_house {
     pub mod hosting {
         pub fn add_to_waitlist() {}
     }
}
pub fn eat_at_restaurant() {
     // 绝对路径
     crate::front_of_house::hosting::add_to_waitlist();
     // 相对路径
     front_of_house::hosting::add_to_waitlist();
}

(2)使用以 super 开头的相对路径

fn deliver_order() {}
mod back_of_house {
     fn fix_incorrect_order() {
         cook_order();
         super::deliver_order();
     }
     fn cook_order() {}
}

(3)使用外部箱

必须先添加依赖。在Cargo.toml中添加外部箱所在的包

比如,

[dependencies]
rand = "0.8.5"

Cargo要从 crates.io 下载 rand 和其依赖。

这样就可以使用绝对路径使用外部箱了

use rand::Rng;
fn main() {
    let secret_number = rand::thread_rng().gen_range(1..101);
}

(4)std标准库

std也是外部箱。因为标准库随Rust语言一同分发,无需修改 Cargo.toml 来引入 std

比如,

let mut guess = String::new();
std::io::stdin().read_line(&mut guess).expect("failed readline");

2.use语句

无论是使用绝对路径还是相对路径都不便,我们可以使用 use 关键字创建一个短路径。

(1)use关键字将模块标识符引入当前作用域:

实例

mod nation {
    pub mod government {
        pub fn govern() {}
    }
}
use crate::nation::government::govern;
fn main() {
    govern();
}

use关键字把govern标识符导入到了当前的模块下,可以直接使用。

(2)可以使用use as为标识符添加别名:

实例

mod nation {
    pub mod government {
        pub fn govern() {}
    }
    pub fn govern() {}
}
use crate::nation::government::govern;
use crate::nation::govern as nation_govern;
fn main() {
    nation_govern();
    govern();
}

这里有两个govern函数,一个是nation下的,一个是government下的,我们用as将nation下的取别名nation_govern。两个名称可以同时使用。

(3)use关键字可以与pub关键字配合使用:

实例

mod nation {
    pub mod government {
        pub fn govern() {}
    }
    pub use government::govern;
}
fn main() {
    nation::govern();
}

(4)使用大括号引入相同模块的多个子模块,可以显著减少 use 语句的数量

比如,

use std::{cmp::Ordering, io};

(5)使用通配符*引入所有子模块

例子

use std::collections::*;

将 std::collections 中所有公有项引入当前作用域

(三)将模块分割进不同文件

到目前为止,都是在一个文件中定义多个模块。当模块变得更大时,你可能想要将它们移动到单独的文件中。

例如,

文件名: src/lib.rs
mod front_of_house;	//声明front_of_house模块,其内容将位于src/front_of_house.rs
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
     hosting::add_to_waitlist();
}

文件名: src/front_of_house.rs
pub mod hosting {
     pub fn add_to_waitlist() {}
}

在src/front_of_house.rs中定义front_of_house模块

在mod front_of_house后使用分号,而不是代码块,表示在其他文件中定义模块。Rust会在与模块同名的文件中查找模块的代码。

继续重构我们例子,将hosting模块也提取到其自己的文件中

文件名: src/front_of_house.rs
pub mod hosting;

创建一个src/front_of_house目录,在src/front_of_house/hosting.rs文件中定义hosting模块:

文件名: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
相关推荐
古木20192 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法