跟着谷歌安卓团队学习Rust-软件工程模块
大家好,我是梦兽编程。欢迎回来与梦兽编程一起刷Rust的系列。
这是由 Google 的 Android开发团队的分享Rust课程。本课程涵盖了 Rust 的方方面面,从基本语法到泛型和错误处理等高级主题。
该课程的最新版本可以在 google.github.io/comprehensi...
如果你喜欢看梦兽编程的版本可以订阅跟着谷歌安卓团队学Rust订阅最新内容,梦兽编程也期待大家关注我的个人网站。
加入梦兽编程微信群,公众号回复111即可加入交流群与梦兽进行交流。
模块
Rust的模块系统对于软件工程至关重要,因为它提供了一种结构化的方式来组织和封装代码。通过模块化,开发者可以将相关功能分组,减少命名冲突,提高代码的可读性和可维护性。模块的可见性控制允许精确地暴露API,保护内部实现。此外,模块化促进了代码重用,简化了单元测试,并支持并发开发,从而提高了开发效率和软件质量。这种设计灵活性还使得系统更容易适应变化,支持软件的长期演进。简而言之,Rust的模块系统是构建可靠、高效软件的关键工具。
每个软件的入口都是从一个main函数开始的,每个程序最终编译只有一个执行文件。
如果我们的代码都写在一个mian文件中,这是一件多么壮观的场景。你可能需要一台超级计算器才能打开文件进行二次编辑,如果你的项目做的非常非常非常庞大。
所以我们一般都会对代码进行拆分为个个小模块。对其进行二次复用也好,提高可读性也罢。软件工程只不过是让开发者更好的进行开发,机器压根不管你这些。
今天就让我们一起学习Rust的模块之旅吧!
我还是据一个我熟悉的语言javascript或者golang吧。
在node.js中,我们可以使用cmd规程来对我们的代码进行模块导入和到处,js可能是最简单的模块到处模型。它可以自己寻找package.json的path路径。只要你有module.exports就可以使用这种规范。
javascript
// javascript 中
// 导入模块
const path = require('path');
function getName() {
}
// 到处模型
module.exports = {
getName
}
在Rust中要如何实现呢?
rust
mod foo {
pub fn do_something() {
println!("In the foo module");
}
}
mod bar {
pub fn do_something() {
println!("In the bar module");
}
}
fn main() {
foo::do_something();
bar::do_something();
}
在这个例子中,我们可以看到Rust语言不像其他语言一样使用impl之类的关键词,在Rust使用的mod关键词。
在main函数中,可以通过模块名和双冒号(::)来调用这些函数。
当然你也可以在Cargo.toml中加入更多的第三方依赖包,这些依赖包都已经定义好了mod了,你只需要在想使用的地方进行use操作即可,类似c++的语法差不多。
依赖包(Crate)制作与使用
Crate是Rust中的编译单元,分为库crate和二进制crate。库crate编译成共享库,供其他项目调用;二进制crate编译成可执行文件,直接运行。每个crate包含源代码和Cargo.toml配置文件,定义了项目设置和依赖。Crate机制支持代码重用,简化依赖管理,是Rust生态系统的基础。
在项目中创建一个新的目录src/lib,并在其中添加一个lib.rs文件。这个文件将作为我们的库crate的根模块。
rust
// src/lib/lib.rs:
pub fn add_numbers(a: i32, b: i32) -> i32 {
a + b
}
在src目录中,我们已经有了main.rs文件,这是我们的二进制crate。我们将在这个文件中使用我们刚刚创建的库crate。
rust
// src/main.rs:
// 注意早起代码需要加入这行
extern crate my_project; // 在Cargo 0.2018.0之后的版本中,这行代码不再需要
fn main() {
let sum = my_project::add_numbers(3, 5);
println!("The sum is: {}", sum);
}
基于文件夹的模块系统
第一种方式编写模块,我没需要在main.rs中推很多代码,我没如何拆分到每个文件使用呢?
在Rust中,模块的组织通常与文件系统结构相匹配。每个模块对应于文件系统中的一个目录,而模块内部的子模块对应于子目录。Rust使用这种结构来组织代码,使得项目结构清晰且易于理解。
上面我们可以知道Rust中模块是通过mod关键字声明的。
如果你有一个名为src/lib.rs的文件,你可以在其中声明模块:
rust
// src/lib.rs
pub mod submodule;
文件系统层次结构:Rust项目通常遵循以下文件系统层次结构
css
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs
│ └── lib.rs
│ └── modules/
│ ├── mod1.rs
│ └── mod2.rs
├── tests/
│ └── mod_tests.rs
└── benches/
└── bench_tests.rs
在这个结构中,main.rs是二进制crate的入口点,lib.rs是库crate的入口点,而modules目录包含了项目中的其他模块。
模块路径:在Rust中,模块路径用于指定模块的位置。例如,如果你想要使用modules目录下的mod1.rs中的function函数,你可以这样声明:
rust
// 在 src/lib.rs 或 src/main.rs
mod modules;
use modules::mod1::function;
注意模块之家的可见效:模块中的项(如函数、结构体等)默认是私有的。要使它们在模块外部可见,需要使用pub关键字。
使用super和self:在模块路径中,super用于访问父模块,而self用于访问当前模块。
通过文件系统结构来支持这种模块化。这种结构有助于维护大型项目,使得代码更加模块化、可维护和可扩展。几乎现在很多语言的模块系统都安装这个规范。
use 生命
使用use声明:在其他模块中,可以使用use关键字来引入公共模块或项。这允许在当前模块中直接访问这些公共项,而不需要通过模块路径。
假设我们有一个项目结构如下:
css
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs
│ └── my_module/
│ ├── mod1.rs
│ └── mod2.rs
在my_module/mod1.rs中,我们定义了一个公共结构体和一个公共函数:
rust
// my_module/mod1.rs
pub struct MyStruct {
value: i32,
}
impl MyStruct {
pub fn new(value: i32) -> MyStruct {
MyStruct { value }
}
}
pub fn my_function() {
println!("Hello from my_function!");
}
现在,如果我们想在src/main.rs中使用MyStruct和my_function,我们可以在main.rs中使用use声明:
rust
// src/main.rs
use my_module::mod1::{MyStruct, my_function}; // 引入mod1模块中的MyStruct和my_function
fn main() {
let my_struct = MyStruct::new(42);
println!("Struct value: {}", my_struct.value); // 使用MyStruct
my_function(); // 调用my_function
}
这样你就不需要在lib中进行声明mod进行维护了,上面提到的模块路径就是这么一回事。
本文使用 markdown.com.cn 排版