当前位置: 首页 > news >正文

rust 包模块组织结构

一个包(package)可以拥有多个二进制单元包及一个可选的库单元包。随着包内代码规模的增长,你还可以将代码拆分到独立的单元包(crate)中,并将它作为外部依赖进行引用。

RUST提供了一系列的功能来帮助我们管理代码,包括决定哪些细节是暴露的、哪些细节是私有的,以及不同的作用域的命名管理。这些功能有时被统称为模块系统(module system),它们包括:

  • 包(package):一个用于构建、测试并分享单元包的Cargo功能
  • 单元包(crate):一个用于生成库或可执行文件的树形模块结构
  • 模块(module)及use关键字:它们被用于控制文件结构、作用域及路径的私有性
  • 路径(path):一种用于命名条目的方法,这些条目包括结构体、函数和模块等

有几条规则决定了包可以包含哪些东西:首先,一个包中最多只能拥有一个库单元包。其次,包可以拥有多个二进制单元包。最后,包内必须存在至少一个单元包(库单元包或二进制单元包)。

cargo new my-project

当我们执行这条命令时,Cargo会生成一个包并创建相应的Cargo.toml文件。Cargo会默认将src/main.rs视作一个二进制单元包的根节点,这个二进制单元包与包拥有相同的名字。同样地,假设包的目录中包含文件src/lib.rsCargo也会自动将其视作与包同名的库单元包的根节点。

最初生产的包只包含源文件src/main.rs,这也意味着只包含一个名为my-project的二进制单元包。而假设包中同时存在src/main.rssrc/lib.rs,那么其中就会分别存在一个二进制单元包和一个库单元包,它们用于与包相同的名字。我们可以在路径src/bin下添加源文件来创建出更多的二进制单元包,这个路径下的每个源文件都会被视作单独的二进制单元包。

我们依赖的外部包,比如提供生成随机数功能的rand包就属于单元包。将单元包的功能保留在它们自己的作用域中有助于指明某个特定功能来源于哪个单元包,并避免可能得命名冲突。

定义模块来控制作用域及私有性

通过下面的方式创建一个库单元包,RUST也默认生成了单元测试的代码

cargo new --lib restaurant
// src/lib.rs
mod front_of_house {mod host {fn add_to_waitlist() {}fn seat_at_table() {}}mod serving {fn take_order() {}fn serve_order() {}fn take_payment() {}}
}

通过mod关键字开头来定义一个模块,接着指明这个模块的名称,并在其后使用一对花括号来包裹模块体。模块内可以定义其他模块,同样也可以包含其它条目的定义,比如结构体、枚举、常量等。

我们前面提到过,src/main.rssrc/lib.rs被称为单元包的根节点,因为这两个文件的内容各自组成了一个名为crate的模块,并位于单元包模块结构的根部。这个模块结构也被称为模块树(module tree),整个模块树都被放置在一个名为crate的隐式根模块下:

crate└── front_of_house     ├── hosting     │   ├── add_to_waitlist     │   └── seat_at_table     └── serving     ├── take_order     ├── serve_order     └── take_payment

为了在RUST模块树中找到某个条目,我们需要指定条目的路径,有两种形式:

  • 使用单元包或字面量crate从根节点开始的绝对路径
  • 使用slefsuper或内部标识符从当前模块开始的相对路径

绝对路径与相对路径都至少由一个标识符组成,标识符之间使用双冒号(::)分隔。

// src/lib.rs
pub fn eat_at_restaurant() {// 绝对路径crate::front_of_house::host::add_to_waitlist();// 相对路径front_of_house::host::add_to_waitlist();
}

我们使用绝对路径和相对路径来调用add_to_waitlist函数,大部分开发者更倾向使用绝对路径,因为我们往往会彼此独立地移动代码的定义与代码调用。

这段代码编译器报错,因为模块host是私有的。模块不仅仅被用于组织代码,同时还定义了RUST的私有边界(privacy boundary):外部代码无法访问那些由私有边界封装的细节。

RUST中的所有条目(函数、方法、结构体、枚举、模块及常量)默认都是私有的。处于父模块中的条目无法使用子模块中的私有条目,但子模块中的条目可以使用祖先模块中的条目。虽然子模块包装并隐藏了自身的实现细节,但它却依然能够感知当前定义环境的上下文。

我们需要给hosting模块添加pub关键字,之后我们便拥有了访问hosting子模块的权利。然后,我们再给add_to_waitlist添加pub关键字,私有性问题就解决了。整个过程中,编译正常通过而front_of_house模块并没有声明为pub,是因为front_of_houseeat_at_restaurant被定义在相同的模块下。

fn server_oreder() {}mod back_of_house {fn fix_incorrent_order() {cook_order();super::server_oreder();}fn cook_order() {}
}

代码从父模块开始构建相对路径,这一方式需要在路径起始处使用super关键字。这有些类似于在文件系统中使用..语法开始一段路径。例子中,我们通过super关键字来跳转至back_of_house的父模块,也就是根模块。

结构体及枚举声明为公开

当我们在结构体定义前使用pub时,结构体本身就成为了公共结构体,但它的字段依旧保持了私有状态。我们可以逐一决定是否将某个字段公开。

枚举与结构体不同,由于枚举只有在所有变体都公开时才能实现最大的功效,而为所有枚举变体添加pub则显得繁琐,因此所有的枚举变体默认都是公开的。但前提是我们将枚举声明为公开。

use将路径导入作用域

基于路径调用函数的写法使用起来有些重复和冗长,我们可以借助use关键字将路径引入作用域,并像使用本地条目一样来调用路径中的条目。

mod front_of_house {pub mod host {pub fn add_to_waitlist() {}}
}use crate::front_of_house::host;pub fn eat_at_restaurant() {host::add_to_waitlist();
}

通过在单元包的根节点下添加use crate::front_of_house::hosthost成为该作用域下的一个有效名字,就如同host模块被定义在根节点下一样。当然,使用use将路径引入作用域时也需要遵守私有性规则。

实例中使用了绝对路径,使用相对路径也是可以的:use front_of_house::host

使用as提供新的名称

使用use将同名类型引入作用域时,可以在路径后使用as关键字为类型指定一个新的本地名字,也就是别名。

use std::fmt::Result;
use std::io::Result as IoResult;

使用嵌套的路径来清理众多use语句

use std::io;
use std::io::Write;

这两条拥有共同的前缀std::io,该前缀还是第一条路径本身。可以在嵌套路径中使用self将两条路径合并至一行use语句中。

use std::io::{self, Write};
http://www.lryc.cn/news/255395.html

相关文章:

  • 深入浅出:HTTPS单向与双向认证及证书解析20231208
  • 水利安全监测方案——基于RTU200的解决方案
  • 安卓开发学习---kotlin版---笔记(一)
  • 挑选在线客服系统的七大注意事项
  • 剧本杀小程序搭建:打造线上剧本杀新体验
  • 机器学习实战:预测波士顿房价
  • 基于个微机器人的开发
  • 程序员学习方法
  • VUE+THREE.JS 点击模型相机缓入查看模型相关信息
  • cpu 300% 爆满 内存占用不高 排查
  • Halcon 简单的ORC 字体识别
  • 12月7日作业
  • 【腾讯云HAI域探密】- AIGC应用助力企业降本增效之路
  • 云原生之深入解析如何限制Kubernetes集群中文件描述符与线程数量
  • Django的Auth模块
  • 敏捷开发方法
  • vue 前端实现login页登陆 验证码
  • python 涉及opencv mediapipe知识,眨眼计数 供初学者参考
  • HTTP 和 HTTPS的区别
  • 从零开始训练一个ChatGPT大模型(低资源,1B3)
  • 从文字到使用,一文读懂Kafka服务使用
  • 什么是https加密协议?
  • 0012Java程序设计-ssm医院预约挂号及排队叫号系统
  • PaddleClas学习3——使用PPLCNet模型对车辆朝向进行识别(c++)
  • 学习记录---kubernetes中备份和恢复etcd
  • 使用单例模式+观察者模式实现参数配置实时更新
  • 区块链实验室(28) - 拜占庭节点劫持区块链仿真
  • 聊聊AsyncHttpClient的ChannelPool
  • [MySQL] MySQL复合查询(多表查询、子查询)
  • [架构之路-256]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件系统不同层次的复用与软件系统向越来越复杂的方向聚合