深入理解 Rust 模块中的路径与公开性:绝对路径、相对路径和 `pub` 的应用

news2025/2/8 20:54:01

1. 路径的两种形式:绝对路径与相对路径

在 Rust 中,路径类似于文件系统中的目录路径,用来告诉编译器去哪里查找某个项。路径主要有两种形式:

  • 绝对路径
    绝对路径从 crate 的根开始。对于当前 crate 的代码,绝对路径以关键字 crate 开头;对于外部 crate,则以该 crate 的名称开始。
    示例:假设我们要调用 add_to_waitlist 函数,其完整的绝对路径可能是:

    crate::front_of_house::hosting::add_to_waitlist();
    
  • 相对路径
    相对路径则是从当前模块出发,利用 selfsuper 或直接用模块名称来指定路径。例如,如果当前模块与 front_of_house 同级,可以直接这样调用:

    front_of_house::hosting::add_to_waitlist();
    

选择使用哪种路径主要取决于代码重构时模块之间可能的移动。如果函数与其被调用项经常会一起移动,那么使用相对路径可能更方便;否则,绝对路径则提供了更稳定的引用。

2. 通过路径调用函数:一个示例

假设我们有如下模块结构(部分代码摘自 Listing 7-1):

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

我们希望在同一个 crate 根中定义一个名为 eat_at_restaurant 的函数来调用 add_to_waitlist 函数。可以使用两种不同的路径来实现这一目标:

  • 使用绝对路径
    pub fn eat_at_restaurant() {
        // 从 crate 根开始,使用绝对路径调用 add_to_waitlist
        crate::front_of_house::hosting::add_to_waitlist();
    }
    
  • 使用相对路径
    pub fn eat_at_restaurant() {
        // 从当前模块开始,直接用模块名调用
        front_of_house::hosting::add_to_waitlist();
    }
    

无论选择哪种方式,关键在于准确表达代码在模块树中的位置。

3. 模块私有性问题:编译错误的根源

在实际编译过程中,可能会遇到类似下面的错误:

error[E0603]: module `hosting` is private

这表明即使路径写得正确,由于 Rust 默认将模块中的所有项设置为私有,外部模块无法直接访问 hosting 模块中的内容。为了让父模块中的 eat_at_restaurant 能够调用 add_to_waitlist,不仅需要使 hosting 模块变为公共(使用 pub mod hosting;),还需要将 add_to_waitlist 函数本身声明为 pub

例如,假设我们的代码如下:

// 在 src/lib.rs 中
mod front_of_house {
    // 将 hosting 模块标记为 pub,让外部可以访问该模块
    pub mod hosting {
        // add_to_waitlist 函数默认是私有的,需要加 pub
        pub fn add_to_waitlist() {
            println!("Adding to waitlist");
        }
    }
}

pub fn eat_at_restaurant() {
    // 两种路径均可使用,因为模块与函数都已经公开
    crate::front_of_house::hosting::add_to_waitlist();
    // 或者:
    front_of_house::hosting::add_to_waitlist();
}

只有同时使用 pub 将模块和函数公开,调用代码才能通过编译。

4. 使用 super 构造相对路径

有时我们需要引用父模块中的项,此时可以使用 super 关键字,其效果类似于文件路径中的 ..。例如,在 back_of_house 模块中,假设有一个函数 fix_incorrect_order 需要调用父模块中的 deliver_order

mod back_of_house {
    pub fn fix_incorrect_order() {
        // 使用 super 关键字引用父模块中的 deliver_order
        super::deliver_order();
    }
}

fn deliver_order() {
    println!("Order delivered!");
}

这种写法不仅直观,而且在模块重构时可以减少修改路径的地方,因为父子模块之间的相对关系保持不变。

5. 让 Struct 和 Enum 成为公共接口

除了函数和模块,结构体(structs)和枚举(enums)也是模块系统中常见的构建块。不过需要注意的是:

  • 结构体(structs)
    使用 pub 标记结构体可以使其整体公开,但结构体的字段默认仍然是私有的。如果希望外部代码能够访问或修改某些字段,需要在字段前也加上 pub

    pub struct Breakfast {
        pub toast: String,         // 公开字段
        seasonal_fruit: String,    // 私有字段
    }
    
    impl Breakfast {
        // 提供公共关联函数来构造实例
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: toast.to_string(),
                seasonal_fruit: String::from("peach"),
            }
        }
    }
    

    这样,外部代码可以访问 toast 字段,但无法直接修改 seasonal_fruit

  • 枚举(enums)
    与结构体不同,枚举在声明为 pub 后,其所有变体默认都为公共的:

    pub enum Appetizer {
        Soup,
        Salad,
    }
    

    外部代码可以直接使用 Appetizer::SoupAppetizer::Salad,而无需单独标记每个变体为公共。

6. 小结与最佳实践

通过本文,我们了解了以下关键概念:

  • 路径的形式:绝对路径从 crate 或外部 crate 开始,而相对路径则以当前模块为起点,必要时可使用 selfsuper 等关键字。
  • 模块私有性:Rust 默认将所有项设为私有,使用 pub 可以有选择地暴露接口,从而形成稳定的公共 API。
  • 最佳实践
    • 在设计公共 API 时,将模块树组织在 src/lib.rs 中,确保只有明确标记为 pub 的项可供外部使用。
    • 在项目中使用绝对路径可以更好地分离代码定义和使用,减少因代码重构导致的路径修改。
    • 利用 super 构造相对路径,使得父子模块之间的引用更为灵活和稳健。

通过这些机制,Rust 为开发者提供了一套强大而灵活的模块系统,既能保持内部实现的封装,又能方便外部代码调用需要暴露的接口。

希望这篇博客能帮助你更深入地理解 Rust 模块中的路径引用与公开性设置,从而编写出更清晰、健壮的代码。Happy coding!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2294936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Day 16]螺旋遍历二维数组

今天我们看一下力扣上的这个题目:146.螺旋遍历二维数组 题目描述: 给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。 螺旋遍历:从左上角开始,按照 向右、向下、向左、向上 的顺序 依次 提取元素&#xff0c…

【教程】docker升级镜像

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 自动升级 手动升级 无论哪种方式,最重要的是一定要通过-v参数做数据的持久化! 自动升级 使用watchtower,可…

使用jmeter进行压力测试

使用jmeter进行压力测试 jmeter安装 官网安装包下载,选择二进制文件,解压。 tar -xzvf apache-jmeter-x.tgz依赖jdk安装。 yum install java-1.8.0-openjdk环境变量配置,修改/etc/profile文件,添加以下内容。 export JMETER/…

链表和 list

一、单链表的模拟实现 1.实现方式 链表的实现方式分为动态实现和静态实现两种。 动态实现是通过 new 申请结点,然后通过 delete 释放结点的形式构造链表。这种实现方式最能体 现链表的特性; 静态实现是利用两个数组配合来模拟链表。一个表示数据域&am…

【AI大模型】Ubuntu18.04安装deepseek-r1模型+服务器部署+内网访问

以下内容主要参考博文:DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」 - 程序设计实验室 - 博客园 安装 ollama Download Ollama on Linux curl -fsSL https://ollama.com/install.sh | sh 配置 ollama 监听地址 ollama 安装后…

cmd执行mysql命令

安装mysql之后如果想使用cmd执行mysql命令,需要怎么操作呢,下面一起看一下。 安装mysql之后,如果直接去cmd窗口执行MySQL命令,窗口可能会提示mysql不是可执行命令。 需要配置系统的环境变量,将mysql的安装路径配置系…

网络安全威胁框架与入侵分析模型概述

引言 “网络安全攻防的本质是人与人之间的对抗,每一次入侵背后都有一个实体(个人或组织)”。这一经典观点概括了网络攻防的深层本质。无论是APT(高级持续性威胁)攻击、零日漏洞利用,还是简单的钓鱼攻击&am…

详细教程 | 如何使用DolphinScheduler调度Flink实时任务

Apache DolphinScheduler 非常适用于实时数据处理场景,尤其是与 Apache Flink 的集成。DolphinScheduler 提供了丰富的功能,包括任务依赖管理、动态调度、实时监控和日志管理,能够有效简化 Flink 实时任务的管理和部署。通过 DolphinSchedule…

【通俗易懂说模型】线性回归(附深度学习、机器学习发展史)

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

【R语言】apply函数族

在R语言中使用循环操作时是使用自身来实现的,效率较低。所以R语言有一个符合其统计语言出身的特点:向量化。R语言中的向量化运用了底层的C语言,而C语言的效率比高层的R语言的效率高。 apply函数族主要是为了解决数据向量化运算的问题&#x…

传统营销架构在当下如何进行优化转型?

随着市场环境的变化和数字技术的发展,传统营销架构越来越难以适应当下的营销市场。为了适应新时代的要求,企业也需要对营销架构进行优化转型。企业主可以着手从哪些方面进行调整呢?下面就来一同探讨下。 一、强调扁平化原则 扁平化与去中心化…

QMK启用摇杆和鼠标按键功能

虽然选择了触摸屏,我仍选择为机械键盘嵌入摇杆模块,这本质上是对"操作连续性"的执着。   值得深思的是,本次开发过程中借助DeepSeek的代码生成与逻辑推理,其展现的能力已然颠覆传统编程范式,需求描述可自动…

计算机网络-SSH基本原理

最近年底都在忙,然后这两天好点抽空更新一下。前面基本把常见的VPN都学习了一遍,后面的内容应该又继续深入一点。 一、SSH简介 SSH(Secure Shell,安全外壳协议)是一种用于在不安全网络上进行安全远程登录和实现其他安…

yolov11模型在Android设备上运行【踩坑记录】

0) 参考资料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) :将xxx.pt模型转化成 xxx.onnx ONNX(Ope…

win编译openssl

一、perl执行脚本 1、安装perl脚本 perl安装 2、配置perl脚本 perl Configure VC-WIN32 no-asm no-shared --prefixE:\openssl-x.x.x\install二、编译openssl 1、使用vs工具编译nmake 如果使用命令行nmake编译会提示“无法打开包括文件: “limits.h”“ 等错误信息 所以…

【B站保姆级视频教程:Jetson配置YOLOv11环境(七)Ultralytics YOLOv11配置】

Jetson配置YOLOv11环境(7)Ultralytics YOLOv11环境配置 文章目录 1. 下载YOLOv11 github项目2. 安装ultralytics包3. 验证ultralytics安装3.1 下载yolo11n.pt权重文件3.2 推理 1. 下载YOLOv11 github项目 创建一个目录,用于存放YOLOv11的项目…

硬核技术:小程序能够调用手机的哪些传感器

一、加速度传感器 小程序可以调用手机的加速度传感器来检测设备的运动状态。加速度传感器能够测量设备在三个轴(X、Y、Z)上的加速度变化。通过分析这些数据,小程序可以实现一些功能,如运动检测、步数统计、游戏中的动作感应等。 健…

Day 31 卡玛笔记

这是基于代码随想录的每日打卡 491. 非递减子序列 给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素,如出现两个整数相等&#xff0…

【蓝桥杯嵌入式】4_key:单击+长按+双击

全部代码网盘自取 链接:https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码:3ii2 1、电路图 将4个按键的引脚设置为input,并将初始状态设置为Pull-up(上拉输入) 为解决按键抖动的问题,我们…

Nginx进阶篇 - nginx多进程架构详解

文章目录 1. nginx的应用特点2. nginx多进程架构2.1 nginx多进程模型2.2 master进程的作用2.3 进程控制2.4 worker进程的作用2.5 worker进程处理请求的过程2.6 nginx处理网络事件 1. nginx的应用特点 Nginx是互联网企业使用最为广泛的轻量级高性能Web服务器,其特点是…