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() {}
相关推荐
腾讯TNTWeb前端团队26 分钟前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰4 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪4 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪4 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy5 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom5 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom5 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom5 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom6 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom6 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试