Rust

2025年07月19日更新 7 人订阅
原价: ¥ 6 限时优惠
专栏简介 Rust编程语言之错误处理 Rust 语言之 flod Rust编程语言之Cargo、Crates.io详解 Rust编程语言之枚举与模式匹配 Rust语言 - 接口设计的建议之受约束(Constrained) Rust编程语言之无畏并发 Rust语言 - 接口设计的建议之灵活(flexible) Rust语言 - 接口设计的建议之显而易见(Obvious) Rust语言 - 接口设计的建议之不意外(unsurprising) Rust 实战:构建实用的 CLI 工具 HTTPie Rust编程语言学习之高级特性 Rust内存管理揭秘:深度剖析指针与智能指针 解决Rust中数组和切片的编译时大小问题 《Rust编程之道》学习笔记一 Rust Async 异步编程 简易教程 使用 Async Rust 构建简单的 P2P 节点 Rust编程语言入门之模式匹配 Rust async 编程 Rust编程语言之编写自动化测试 Rust编程语言之函数式语言特性:迭代器和闭包 《Rust编程之道》学习笔记二 Rust Tips 比较数值 使用 Rust 开发一个微型游戏 Rust编程初探:深入理解Struct结构体 深入理解Rust中的内存管理:栈、堆与静态内存详解 深入理解 Rust 结构体:经典结构体、元组结构体和单元结构体的实现 深入掌握 Rust 结构体:从模板到实例化的完整指南 深入理解Rust中的结构体:逻辑与数据结合的实战示例 深入理解 Rust 枚举:从基础到实践 掌握Rust字符串的精髓:String与&str的最佳实践 全面解析 Rust 模块系统:实战案例与应用技巧 Rust 中的 HashMap 实战指南:理解与优化技巧 掌握Rust模式匹配:从基础语法到实际应用 Rust 中的面向对象编程:特性与实现指南 深入理解 Rust 的 Pin 和 Unpin:理论与实践解析 Rust Trait 与 Go Interface:从设计到实战的深度对比 从零开始:用 Rust 和 Axum 打造高效 Web 应用 Rust 错误处理详解:掌握 anyhow、thiserror 和 snafu Rust 如何优雅实现冒泡排序 链表倒数 K 节点怎么删?Python/Go/Rust 实战 用 Rust 玩转数据存储:JSON 文件持久化实战 Rust实战:打造高效字符串分割函数 如何高效学习一门技术:从知到行的飞轮效应 Rust 编程入门:Struct 让代码更优雅 Rust 编程:零基础入门高性能开发 用 Rust 写个猜数游戏,编程小白也能上手! Rust 入门教程:变量到数据类型,轻松掌握! 深入浅出 Rust:函数、控制流与所有权核心特性解析 从零开始:用 Rust 和 Axum 打造高效 Web 服务 Rust 集合类型解析:Vector、String、HashMap 深入浅出Rust:泛型、Trait与生命周期的硬核指南 Rust实战:博物馆门票限流系统设计与实现 用 Rust 打造高性能图片处理服务器:从零开始实现类似 Thumbor 的功能 Rust 编程入门实战:从零开始抓取网页并转换为 Markdown 深入浅出 Rust:高效处理二进制数据的 Bytes 与 BytesMut 实战 Rust智能指针:解锁内存管理的进阶之道 用 Rust 打造命令行利器:从零到一实现 mini-grep 解锁Rust代码组织:轻松掌握Package、Crate与Module Rust 所有权:从内存管理到生产力释放 深入解析 Rust 的面向对象编程:特性、实现与设计模式 Rust + Protobuf:从零打造高效键值存储项目 bacon 点燃 Rust:比 cargo-watch 更爽的开发体验 用 Rust 打造微型游戏:从零开始的 Flappy Dragon 开发之旅 函数式编程的Rust之旅:闭包与迭代器的深入解析与实践 探索Rust编程之道:从设计哲学到内存安全的学习笔记 精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用 Rust 避坑指南:搞定数值比较,别再让 0.1 + 0.2 != 0.3 困扰你! 告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力 告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践 Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式 Rust 网络编程实战:用 Tokio 手写一个迷你 TCP 反向代理 (minginx) 保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增 不止于后端:Rust 在 Web 开发中的崛起之路 (2024数据解读) Rust核心利器:枚举(Enum)与模式匹配(Match),告别空指针,写出优雅健壮的代码 Rust 错误处理终极指南:从 panic! 到 Result 的优雅之道 想用 Rust 开发游戏?这份超详细的入门教程请收好! 用 Rust 实现 HTTPie:一个现代 CLI 工具的构建过程 Rust 异步实战:从0到1,用 Tokio 打造一个高性能并发聊天室 深入 Rust 核心:彻底搞懂指针、引用与智能指针 Rust 生产级后端实战:用 Axum + sqlx 打造高性能短链接服务 深入 Rust 内存模型:栈、堆、所有权与底层原理

解锁Rust代码组织:轻松掌握Package、Crate与Module

解锁Rust代码组织:轻松掌握Package、Crate与Module想在2025年成为Rust编程的佼佼者?代码组织是Rust开发的第一道门槛,也是释放其高效与安全潜力的关键!Rust的模块系统通过Package、Crate和Module,为开发者提供了优雅而强大的代码管理方式。本文将带你轻松解

解锁Rust代码组织:轻松掌握Package、Crate与Module

想在2025年成为Rust编程的佼佼者?代码组织是Rust开发的第一道门槛,也是释放其高效与安全潜力的关键!Rust的模块系统通过Package、Crate和Module,为开发者提供了优雅而强大的代码管理方式。本文将带你轻松解锁Rust代码组织的秘密,从Package与Crate的定义到Module的灵活应用,手把手带你掌握Rust模块系统的核心技巧。无论你是初学者还是进阶开发者,这篇干货满满的指南都将助你快速上手,编写更清晰、更高效的Rust代码!

本文以通俗易懂的方式,系统讲解了Rust编程语言中Package、Crate和Module的定义与使用方法。文章从Rust代码组织的基本原则入手,详细解析了Package与Crate的类型及Cargo工具的惯例,深入剖析Module的作用、路径(Path)的使用规则,以及pub和use关键字的灵活运用。同时,介绍了如何通过拆分模块到不同文件提升代码可维护性。无论你是想快速入门Rust,还是希望优化代码结构,这篇指南都将为你提供清晰的思路和实用的技巧。

一、Package、Crate、定义 Module

Rust的代码组织

  • 代码组织主要包括:
    • 哪些细节可以暴露,哪些细节是私有的
    • 作用域内哪些名称有效
  • 模块系统:
    • Package(包):Cargo 的特性,让你构建、测试、共享 crate
    • Crate(单元包):一个模块树,它可产生一个library 或可执行文件
    • Module(模块)、use:让你控制代码的组织、作用域、私有路径
    • Path(路径):为struct、function 或 module 等命名的方式

Package 和 Crate

  • Crate 的类型:
    • binary
    • library
  • Crate Root:
    • 是源代码文件
    • Rust编译器从这里开始,组成你的Crate的根Module
  • 一个 Package:
    • 包含1个 Cargo.toml,它描述了如何构建这些Crates
    • 只能包含0-1个 library crate
    • 可以包含任意数量的 binary crate
    • 但必须至少包含一个 crate(library 或 binary)
~/rust
➜ cargo new my-project
     Created binary (application) `my-project` package

~/rust
➜ cd my-project

my-project on  master [?] via 🦀 1.67.1
➜ c  # vscode打开(设置了别名)

my-project on  master [?] via 🦀 1.67.1
➜

Cargo 的惯例

  • src/main.rs:
    • binary crate 的 crate root
    • crate 名与 package 名相同
  • src/lib.rs:
    • package 包含一个 library crate
    • library crate 的 crate root
    • crate 名 与 package 名相同
  • Cargo 把 crate root 文件交给 rustc 来构建 library 或 binary
  • 一个Package可以同时包含 src/main.rs和src/lib.rs
    • 一个 binary crate,一个 library crate
    • 名称与package名相同
  • 一个Package可以有多个 binary crate:
    • 文件放在 src/bin
    • 每个文件是单独的 binary crate

Crate 的作用

  • 将相关功能组合到一个作用域内,便于在项目间进行分享
    • 防止冲突
  • 例如 rand crate,访问它的功能需要通过它的名字:rand

定义 module 来控制作用域和私有性

  • Module:
    • 在一个 crate 内,将代码进行分组
    • 增加可读性,易于复用
    • 控制项目(item) 的私有性。public、private
  • 建立 module:
    • mod 关键字
    • 可嵌套
    • 可包含其它项(struct、enum、常量、trait、函数等)的定义

Module

  • lib.rs 文件
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}
  • Src/main.rs 和 src/lib.rs 叫做 crate roots:
    • 这两个文件(任意一个)的内容形成了名为crate 的模块,位于整个模块树的根部
crate
 - front_of_house
   - hosting
     - add_to_waitlist
     - seat_at_table
      - serving
        - take_order
        - serve_order
        - take_payment

二、路径 Path

路径(Path)

  • 为了在Rust的模块中找到某个条目,需要使用路径
  • 路径的两种形式:
    • 绝对路径:从 crate root 开始,使用 crate 名或字面值 crate
    • 相对路径:从当前模块开始,使用 self,super 或当前模块的标识符
  • 路径至少由一个标识符组成,标识符之间使用 ::。(定义和使用一起移动使用相对路径)

私有边界(privacy boundary)

  • 模块不仅可以组织代码,还可以定义私有边界
  • 如果想把函数或 struct等设为私有,可以将它放到某个模块中
  • Rust中所有的条目(函数、方法、struct、enum、模块、常量)默认是私有的
  • 父级模块无法访问子模块中的私有条目
  • 子模块里可以使用所有祖先模块中的条目

pub 关键字

  • 使用pub关键字来将某些条目标记为公共的
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub fn eat_at_restautant() {
    crate::front_of_house::hosting::add_to_waitlist();

    front_of_house::hosting::add_to_waitlist();
}

三、路径 Path (第二部分)

super 关键字

  • Super: 用来访问父级模块路径中的内容,类似文件系统中的 ..
fn serve_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        super::serve_order();
        crate::serve_order();
    }

    fn cook_order() {}
}

pub struct

  • pub 放在 struct 前:
    • Struct 是公共的
    • struct 的字段默认是私有的
mod back_of_house {
    pub struct Breakfast {

    }
}
  • struct 的字段需要单独设置 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_restautant() {
    let mut meal = back_of_house::Breakfast::summer("Rye");
    meal.toast = String::from("Wheat");
    println!("I'd like {} toast please", meal.toast);
    meal.seasonal_fruit = String::from("blueberries"); // 私有的 报错
}

pub enum

  • pub 放在 enum 前:
    • enum 是公共的
    • enum 的变体也都是公共的
mod back_of_house {
  pub enum Appetizer {
    Soup,
    Salad,
  }
}

四、use 关键字

use 关键字

  • 可以使用 use 关键字将路径导入到作用域内
    • 仍遵循私有性规则
mod front_of_house {
  pub mod hosting {
    pub fn add_to_waitlist() {}
  }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
}
  • 使用 use 来指定相对路径
mod front_of_house {
  pub mod hosting {
    pub fn add_to_waitlist() {}
  }
}

use front_of_house::hosting;

pub fn eat_at_restaurant() {
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
}

use 的习惯用法

  • 函数:将函数的父级模块引入作用域(指定到父级)
  • struct,enum,其它:指定完整路径(指定到本身)
use std::collections::HashMap;

fn main() {
  let mut map = HashMap::new();
  map.insert(1, 2);
}
  • 同名条目:指定到父级
use std::fmt;
use std::io;

fn f1() -> fmt::Result {}

fn f2() -> io::Result {}

fn main() {}

As 关键字

  • as 关键字可以为引入的路径指定本地的别名
use std::fmt::Result;
use std::io::Result as IoResult;

fn f1() -> Result {}

fn f2() -> IoResult {}

fn main() {}

五、use 关键字(第二部分)

使用pub use 重新导出名称

  • 使用 use 将路径(名称)导入到作用域内后,该名称在此作用域内是私有的
mod front_of_house {
  pub mod hosting {
    pub fn add_to_waitlist() {}
  }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
}
  • pub use:重导出
    • 将条目引入作用域
    • 该条目可以被外部代码引入到它们的作用域

使用外部包(package)

  • Cargo.toml 添加依赖的包(package)
  • use 将特定条目引入作用域
my-project on  master [?] is 📦 0.1.0 via 🦀 1.67.1 
➜ where cargo  
/opt/homebrew/bin/cargo
/opt/homebrew/bin/cargo
/Users/qiaopengjun/.cargo/bin/cargo

my-project on  master [?] is 📦 0.1.0 via 🦀 1.67.1 
➜ cd /Users/qiaopengjun/.cargo 

~/.cargo 
➜ ls
bin      env      registry

~/.cargo 
➜ ls -al       
total 8
drwxr-xr-x   6 qiaopengjun  staff   192 Feb 20 23:17 .
drwxr-x---+ 81 qiaopengjun  staff  2592 Mar 16 13:47 ..
-rw-r--r--@  1 qiaopengjun  staff     0 Feb 15 22:28 .package-cache #
drwxr-xr-x  15 qiaopengjun  staff   480 Mar 10 13:16 bin
-rw-r--r--   1 qiaopengjun  staff   300 Feb 13 23:48 env
drwxr-xr-x@  6 qiaopengjun  staff   192 Feb 20 23:20 registry

~/.cargo 
➜ 

~/.cargo 
➜ touch config    

~/.cargo 
➜ vim config    

Config 文件

[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"

replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

[net]
git-fetch-with-cli = true
~                                                                                                                                                                 
~                                                                                                                                                                                                                                                                                                                              
~                                                                                                                                                                 
~                                                                                                                                                                 
"config" 9L, 221B

Cargo.toml 文件

[package]
name = "my-project"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.8.5"

src/main.rs 文件

use rand::Rng;

fn main() {
    println!("Hello, world!");
}
  • 标准库(std)也被当做外部包
    • 不需要修改 Cargo.toml 来包含 std
    • 需要使用 use 将 std 中的特定条目引入当前作用域
use rand::Rng;
use std::collections::HashMap;

fn main() {
    println!("Hello, world!");
}

使用嵌套路径清理大量的 use 语句

  • 如果使用同一个包或模块下的多个条目
  • 例子:
use std::cmp::Ordering;
use std::io;

fn main() {}
  • 可使用嵌套路径在同一行内将上述条目进行引入:
    • 路径相同的部分::{路径差异的部分}
  • 如果两个use 路径之一是另一个的子路径
    • 使用 self
use std::{cmp::Ordering, io};

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

use std::io::{self, Write};

fn main() {}

通配符 *

  • 使用 * 可以把路径中的所有的公共条目都引入到作用域
  • 注意:谨慎使用
  • 应用场景:
    • 测试。将所有被测试代码引入到 tests 模块
    • 有时被用于预导入(prelude)模块
use std::collections::*

六、将模块拆分为不同文件

将模块内容移动到其他文件

  • 模块定义时,如果模块名后边是“;”,而不是代码块:
    • Rust会从与模块同名的文件中加载内容
    • 模块树的结构不会变化

未拆分前:src/lib.rs 文件

mod front_of_house {
  pub mod hosting {
    pub fn add_to_waitlist() {}
  }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
}

拆分之后:

src/lib.rs 文件

mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
  hosting::add_to_waitlist();
}

src/front_of_house.rs 文件

pub mod hosting;

src/front_of_house/hosting.rs 文件

pub fn add_to_waitlist() {}
  • 随着模块逐渐变大,该技术让你可以把模块的内容移动到其它文件中

总结

Rust的模块系统是构建清晰、高效代码的基石。Package作为项目容器,管理多个Crate;Crate作为编译单元,分为binary和library类型;Module则通过分组与私有性控制,让代码更具可读性与复用性。结合pub、use关键字以及路径规则,开发者可以轻松管理代码作用域;通过模块拆分到不同文件,更能提升大型项目的维护性。掌握这些技巧,你将能轻松驾驭Rust的代码组织之道,为开发高质量项目奠定坚实基础。快来动手实践,解锁Rust编程的无限可能吧!

参考

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论