Rust组织管理,箱Crate包Package和模块module定义和区别,use关键字作用

本文主要是介绍Rust组织管理,箱Crate包Package和模块module定义和区别,use关键字作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Rust 组织管理

任何一门编程语言如果不能组织代码都是难以深入的,几乎没有一个软件产品是由一个源文件编译而成的。

本教程到目前为止所有的程序都是在一个文件中编写的,主要是为了方便学习 Rust 语言的语法和概念。

对于一个工程来讲,组织代码是十分重要的。

Rust 中有三个重要的组织概念:箱、包、模块。

箱(Crate)

"箱"是二进制程序文件或者库文件,存在于"包"中。

"箱"是树状结构的,它的树根是编译器开始运行时编译的源文件所编译的程序。

注意:"二进制程序文件"不一定是"二进制可执行文件",只能确定是是包含目标机器语言的文件,文件格式随编译环境的不同而不同。

包(Package)

当我们使用 Cargo 执行 new 命令创建 Rust 工程时,工程目录下会建立一个 Cargo.toml 文件。工程的实质就是一个包,包必须由一个 Cargo.toml 文件来管理,该文件描述了包的基本信息以及依赖项。

一个包最多包含一个库"箱",可以包含任意数量的二进制"箱",但是至少包含一个"箱"(不管是库还是二进制"箱")。

当使用 cargo new 命令创建完包之后,src 目录下会生成一个 main.rs 源文件,Cargo 默认这个文件为二进制箱的根,编译之后的二进制箱将与包名相同。

模块(Module)

对于一个软件工程来说,我们往往按照所使用的编程语言的组织规范来进行组织,组织模块的主要结构往往是树。Java 组织功能模块的主要单位是类,而 JavaScript 组织模块的主要方式是 function。

这些先进的语言的组织单位可以层层包含,就像文件系统的目录结构一样。Rust 中的组织单位是模块(Module)。

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

这是一段描述法治国家的程序:国家(nation)包括政府(government)、议会(congress)和法院(court),分别有行政、立法和司法的功能。我们可以把它转换成树状结构:

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

在文件系统中,目录结构往往以斜杠在路径字符串中表示对象的位置,Rust 中的路径分隔符是 :: 。

路径分为绝对路径和相对路径。绝对路径从 crate 关键字开始描述。相对路径从 self 或 super 关键字或一个标识符开始描述。例如:

crate::nation::government::govern();

是描述 govern 函数的绝对路径,相对路径可以表示为:

nation::government::govern();

现在你可以尝试在一个源程序里定义类似的模块结构并在主函数中使用路径。

如果你这样做,你一定会发现它不正确的地方:government 模块和其中的函数都是私有(private)的,你不被允许访问它们。


访问权限

Rust 中有两种简单的访问权:公共(public)和私有(private)。

默认情况下,如果不加修饰符,模块中的成员访问权将是私有的。

如果想使用公共权限,需要使用 pub 关键字。

对于私有的模块,只有在与其平级的位置或下级的位置才能访问,不能从其外部访问。

实例

mod nation {pub mod government {pub fn govern() {}}mod congress {pub fn legislate() {}}mod court {fn judicial() {super::congress::legislate();}}
}fn main() {nation::government::govern();
}

这段程序是能通过编译的。请注意观察 court 模块中 super 的访问方法。

如果模块中定义了结构体,结构体除了其本身是私有的以外,其字段也默认是私有的。所以如果想使用模块中的结构体以及其字段,需要 pub 声明:

实例

mod back_of_house {pub struct Breakfast {pub toast: String,seasonal_fruit: String,}impl Breakfast {pub fn summer(toast: &str) -> Breakfast {Breakfast {toast: String::from(toast),seasonal_fruit: String::from("peaches"),}}}
}
pub fn eat_at_restaurant() {let mut meal = back_of_house::Breakfast::summer("Rye");meal.toast = String::from("Wheat");println!("I'd like {} toast please", meal.toast);
}
fn main() {eat_at_restaurant()
}

运行结果:

I'd like Wheat toast please

枚举类枚举项可以内含字段,但不具备类似的性质:

实例

mod SomeModule {pub enum Person {King {name: String},Queen}
}fn main() {let person = SomeModule::Person::King{name: String::from("Blue")};match person {SomeModule::Person::King {name} => {println!("{}", name);}_ => {}}
}

运行结果:

Blue

难以发现的模块

使用过 Java 的开发者在编程时往往非常讨厌最外层的 class 块——它的名字与文件名一模一样,因为它就表示文件容器,尽管它很繁琐但我们不得不写一遍来强调"这个类是文件所包含的类"。

不过这样有一些好处:起码它让开发者明明白白的意识到了类包装的存在,而且可以明确的描述类的继承关系。

在 Rust 中,模块就像是 Java 中的类包装,但是文件一开头就可以写一个主函数,这该如何解释呢?

每一个 Rust 文件的内容都是一个"难以发现"的模块。

让我们用两个文件来揭示这一点:

main.rs 文件

// main.rs
mod second_module;fn main() {println!("This is the main module.");println!("{}", second_module::message());
}

second_module.rs 文件

// second_module.rs
pub fn message() -> String {String::from("This is the 2nd module.")
}

运行结果:

This is the main module.
This is the 2nd module.

use 关键字

use 关键字能够将模块标识符引入当前作用域:

实例

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

这段程序能够通过编译。

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

这样就解决了局部模块路径过长的问题。

当然,有些情况下存在两个相同的名称,且同样需要导入,我们可以使用 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。两个名称可以同时使用。

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

实例

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

引用标准库

Rust 官方标准库字典:List of all items in this crate

在学习了本章的概念之后,我们可以轻松的导入系统库来方便的开发程序了:

实例

use std::f64::consts::PI;fn main() {println!("{}", (PI / 2.0).sin());
}

运行结果:

1

所有的系统库模块都是被默认导入的,所以在使用的时候只需要使用 use 关键字简化路径就可以方便的使用了。

这篇关于Rust组织管理,箱Crate包Package和模块module定义和区别,use关键字作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/770304

相关文章

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对