模块暴露
pub 规则
结构,枚举,特征或模块的pub
怎么样? pub 对他们来说是这样的:
- Struct:将结构公开,但项目不公开。要公开一个项目,您也必须为每个项目都写一个
pub
。 - Enum 或者 Trait:一切都公开了。这是有道理的,因为特质是关于赋予某物相同的行为。枚举是关于项目之间的选择的,您需要查看它们才能选择它们。
- Module:第一个模块将是
pub
,因为如果不是 pub,那么任何人都无法触摸其中的任何内容。但是模块内部的模块需要将pub
公开。
因此,让我们在 print_things 中放置一个名为 Billy 的结构。这个结构几乎是所有公开的,但不是完全公开的。该结构是公共的,因此会说发布结构 Billy。里面会有一个名字和 times_to_print。名称不会是公共的,因为我们只希望用户创建名为 "Billy".to_string()
的结构。但是用户可以选择打印次数,这样可以公开显示。看起来像这样:
mod print_things {
use std::fmt::{Display, Debug};
#[derive(Debug)]
pub struct Billy { // Billy is public
name: String, // but name is private.
pub times_to_print: u32,
}
impl Billy {
pub fn new(times_to_print: u32) -> Self { // That means the user needs to use new to create a Billy. The user can only input times_to_print
Self {
name: "Billy".to_string(), // We choose the name - the user can't
times_to_print,
}
}
pub fn print_billy(&self) { // This function prints a Billy
for _ in 0..self.times_to_print {
println!("{:?}", self.name);
}
}
}
pub fn prints_one_thing<T: Display>(input: T) {
println!("{}", input)
}
}
fn main() {
use crate::print_things::*; // Now we use *. This imports everything from print_things
let my_billy = Billy::new(3);
my_billy.print_billy();
}
"Billy"
"Billy"
"Billy"
模块嵌套
在 mod 内部,您可以创建其他 mod。子模块(模块内部的模块)始终可以使用父模块内部的任何模块。您可以在下一个示例中看到这一点,在该示例中,我们在 mod 国家的 mod 省内有一个 mod 城市。您可以想到这样的结构:即使您在一个国家中,也可能不在一个省中。即使您在省份中,也可能不在城市中。但是,如果您在城市中,那么您将在其省份中,并且您是其国家/地区。
mod country { // The main mod doesn't need pub
fn print_country(country: &str) { // Note: this function isn't public
println!("We are in the country of {}", country);
}
pub mod province { // Make this mod public
fn print_province(province: &str) { // Note: this function isn't public
println!("in the province of {}", province);
}
pub mod city { // Make this mod public
pub fn print_city(country: &str, province: &str, city: &str) { // This function is public though
crate::country::print_country(country);
crate::country::province::print_province(province);
println!("in the city of {}", city);
}
}
}
}
fn main() {
crate::country::province::city::print_city("Canada", "New Brunswick", "Moncton");
}
有趣的是,print_city 可以访问 print_province 和 print_country。这是因为 mod city 在其他 mod 内。它不需要在 print_province 前面的 pub 来使用它。这是有道理的:城市不需要在省内和国家内做任何事情。您可能注意到了 crate::country::province::print_province(province);
很长,当我们在模块内部时,我们可以使用 super 从上方引入项目。实际上,“超级”一词本身的意思是“在…之上”,就像在“高级”中一样。在我们的示例中,我们只使用了一次函数,但是如果您再使用一次,则导入是个好主意。如果它使您的代码更易于阅读,即使您只使用一次该函数,也是一个好主意。现在的代码几乎相同,但更易于阅读:
mod country {
fn print_country(country: &str) {
println!("We are in the country of {}", country);
}
pub mod province {
fn print_province(province: &str) {
println!("in the province of {}", province);
}
pub mod city {
use super::super::*; // use everything in "above above": that means mod country
use super::*; // use everything in "above": that means mod province
pub fn print_city(country: &str, province: &str, city: &str) {
print_country(country);
print_province(province);
println!("in the city of {}", city);
}
}
}
}
fn main() {
use crate::country::province::city::print_city; // bring in the function
print_city("Canada", "New Brunswick", "Moncton");
print_city("Korea", "Gyeonggi-do", "Gwangju"); // Now it's less work to use it again
}
Re-exporting
我们可以结合使用 pub use
来实现 Re-exporting
。Re-exporting
的字面意思就是重新导出。它的意思是这样的,把深层的 item 导出到上层目录中,使调用的时候,更方便。接口设计中会大量用到这个技术。对于深层引用 a::b::c::d
的例子。我们在 main.rs
中,要调用 d
,得使用 use a::b::c::d;
来调用。而如果我们修改 a/mod.rs
文件为:a/mod.rs
文件内容:
pub mod b;
pub use b::c::d;
那么,我们在 main.rs
中,就可以使用 use a::d;
来调用了。从这个例子来看没觉得方便多少。但是如果开发的一个库中有大量的内容,而且是在不同层次的模块中。那么,通过统一导出到一个地方,就能大大方便接口使用者。