Rust中的模块系统之控制作用域与私有性详解
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>Rust控制作用域与私有性</li><ul class="second_class_ul"><li>模块、路径与 use 关键字简明速查</li><li>实战案例:构建一个示例项目</li><li>分组相关代码:以餐厅系统为例</li></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>Rust控制作用域与私有性</h2><p class="maodian"></p><h3>模块、路径与 use 关键字简明速查</h3>
<p>在开始具体案例之前,我们先来看看 Rust 模块系统的一些基础规则:</p>
<p><strong>从 crate 根开始</strong></p>
<p>编译器首先会在 crate 根(对于库 crate 默认是 <code>src/lib.rs</code>,对于二进制 crate 默认是 <code>src/main.rs</code>)中查找代码。</p>
<p><strong>声明模块</strong></p>
<p>在 crate 根中,可以使用 <code>mod</code> 关键字声明一个模块,例如:</p>
<div class="jb51code"><pre class="brush:bash;">mod garden;</pre></div>
<p>编译器会在以下位置寻找 <code>garden</code> 模块的实现:</p>
<ul><li>内联写在大括号中(代替分号)</li><li>文件 <code>src/garden.rs</code></li><li>文件 <code>src/garden/mod.rs</code></li></ul>
<p><strong>声明子模块</strong></p>
<p>在非 crate 根文件中同样可以声明子模块,例如在 <code>src/garden.rs</code> 中:</p>
<div class="jb51code"><pre class="brush:bash;">mod vegetables;</pre></div>
<p>编译器会依次在以下位置查找:</p>
<ul><li>内联大括号中的代码</li><li>文件 <code>src/garden/vegetables.rs</code></li><li>文件 <code>src/garden/vegetables/mod.rs</code></li></ul>
<p><strong>路径访问模块中的代码</strong></p>
<ul><li>一旦模块被引入 crate 中,可以通过路径来访问其中的代码。</li><li>例如,假设 <code>Asparagus</code> 类型定义在 <code>src/garden/vegetables.rs</code> 中,那么它的完整路径就是:</li></ul>
<div class="jb51code"><pre class="brush:bash;">crate::garden::vegetables::Asparagus</pre></div>
<p><strong>私有性与公开性</strong></p>
<ul><li>默认情况下,模块中的代码对父模块是私有的。</li><li>如果需要让模块或其中的项对外部可见,需要使用 <code>pub</code> 修饰:</li></ul>
<div class="jb51code"><pre class="brush:bash;">pub mod garden;
pub fn some_function() { ... }</pre></div>
<p><code>use</code><strong> 关键字</strong></p>
<p>为了减少长路径的重复输入,可以在作用域内使用 <code>use</code> 关键字创建路径别名:</p>
<div class="jb51code"><pre class="brush:bash;">use crate::garden::vegetables::Asparagus;</pre></div>
<p>从此之后,当前作用域只需使用 <code>Asparagus</code> 即可引用该类型。</p>
<p class="maodian"></p><h3>实战案例:构建一个示例项目</h3>
<p>让我们通过一个示例项目来深入了解模块系统的应用。</p>
<p>假设我们创建了一个二进制 crate,名为 <code>backyard</code>,目录结构如下:</p>
<div class="jb51code"><pre class="brush:plain;">backyard
├── Cargo.lock
├── Cargo.toml
└── src
├── garden
│ └── vegetables.rs
├── garden.rs
└── main.rs</pre></div>
<p><strong>crate 根:src/main.rs</strong></p>
<ul><li>这是项目的入口文件。</li><li>在这里,我们会用 <code>pub mod garden;</code> 告诉编译器在 <code>src/garden.rs</code> 中查找 <code>garden</code> 模块的定义。</li></ul>
<p><strong>模块实现:src/garden.rs</strong></p>
<ul><li>在这个文件中,可以继续声明子模块,例如:</li></ul>
<div class="jb51code"><pre class="brush:bash;">pub mod vegetables;</pre></div>
<p>编译器会自动查找 <code>src/garden/vegetables.rs</code> 中的实现。</p>
<p><strong>子模块:src/garden/vegetables.rs</strong></p>
<ul><li>在这里可以定义 <code>vegetables</code> 模块中具体的结构体、函数等。</li><li>这种文件和模块的组织方式,使得代码结构与文件目录结构非常接近,方便开发者理解和维护项目。</li></ul>
<p class="maodian"></p><h3>分组相关代码:以餐厅系统为例</h3>
<p>模块不仅仅是为了分散代码文件,更重要的是帮助我们将相关代码进行逻辑分组,并明确其作用域和公开性。</p>
<p>下面以一个餐厅系统为例,说明如何利用模块划分前台(front of house)和后台(back of house)的功能。</p>
<p><strong>1.创建项目</strong></p>
<p>运行以下命令创建一个新的库 crate:</p>
<div class="jb51code"><pre class="brush:bash;">cargo new restaurant --lib</pre></div>
<p><strong>2.定义模块结构</strong></p>
<p>在 <code>src/lib.rs</code> 中,我们可以定义如下模块结构:</p>
<div class="jb51code"><pre class="brush:bash;">pub mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
// 实现细节
}
fn seat_at_table() {
// 仅内部使用
}
}
pub mod serving {
pub fn take_order() {
// 实现细节
}
pub fn serve_order() {
// 实现细节
}
pub fn take_payment() {
// 实现细节
}
}
}</pre></div>
<p>如上所示:</p>
<ul><li><code>front_of_house</code> 模块对外公开(<code>pub mod</code>),表示餐厅的前台部分可以被外部调用。</li><li>前台模块下的子模块 <code>hosting</code> 和 <code>serving</code> 也分别使用 <code>pub mod</code> 进行声明,其中某些函数(例如 <code>seat_at_table</code>)保持私有,仅用于模块内部调用。</li></ul>
<p><strong>3.模块树示意</strong></p>
<p>以上代码构成了如下的模块树:</p>
<div class="jb51code"><pre class="brush:plain;">crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment</pre></div>
<p>这种分组方式不仅使代码逻辑清晰,而且对外暴露的接口也非常明确。</p>
<p><strong>4.使用 </strong><code>use</code> <strong>关键字简化调用</strong></p>
<p>在其他模块或二进制 crate 中使用餐厅系统的功能时,可以利用 <code>use</code> 来引入模块:</p>
<div class="jb51code"><pre class="brush:bash;">use crate::front_of_house::hosting;
fn eat_at_restaurant() {
hosting::add_to_waitlist();
}</pre></div>
<p>这大大减少了重复书写长路径的麻烦,并且使代码更易读。</p>
<p class="maodian"></p><h2>总结</h2>
<p>Rust 的模块系统为代码的组织与访问权限控制提供了强大而灵活的机制:</p>
<p><strong>模块声明与文件组织</strong></p>
<ul><li>通过 <code>mod</code> 关键字</li><li>我们可以将代码分散到多个文件中</li><li>而编译器则根据约定自动寻找相应的模块实现</li></ul>
<p><strong>路径与 <code>use</code> 关键字</strong></p>
<ul><li>通过路径,我们可以精确地定位模块中的项;</li><li>而 <code>use</code> 关键字则帮助我们在局部作用域内简化路径引用,提高代码可读性。</li></ul>
<p><strong>私有性与公开性</strong></p>
<ul><li>默认情况下模块中的内容是私有的</li><li>使用 <code>pub</code> 关键字可以有选择地将需要暴露的部分公开</li><li>确保内部实现的封装性</li></ul>
<p><strong>逻辑分组与组织</strong></p>
<ul><li>例如在餐厅系统的例子中,通过前台和后台的模块划分</li><li>不仅使代码结构更清晰,也方便后续功能扩展和维护</li></ul>
<p>掌握这些模块系统的知识,你就能在构建大型项目时轻松管理复杂的代码结构,提高开发效率。</p>
<p>希望这篇博客能帮助你更好地理解 Rust 中的模块及其控制作用域和私有性的机制,开启你在 Rust 世界的模块化编程之旅。</p>
<p>以上为个人经验,希望能给大家一个参考,也希望大家多多支持琼殿技术社区。</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>Rust中自定义Debug调试输出的示例详解</li><li>Rust中的注释使用解读</li><li>Rust中的方法与关联函数使用解读</li><li>Rust之Rhai脚本编程的示例</li><li>Rust中的Trait与Trait Bounds详解</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]