可见性(visibility)
1. 默认可见性
默认情况下,Rust 中的所有项(函数、类型、模块等)都是私有的(private),即它们只能在定义它们的模块内部访问。这可以有效地避免意外的 API 暴露,强制用户使用模块提供的公共接口。
details
mod Math {
const LEN: usize = 1;
static capacity: usize = 1;
fn add(a: usize, b: usize) -> usize {
a + b
}
fn add_and_log(a: usize, b: usize) -> () {
println!("result is {}", add(a, b) + LEN + capacity);
}
}
2. pub
关键字
pub
关键字用于显式地将项标记为公共的(public),使其可以被其他模块访问。在 Rust 中,有几种使用方式:
模块级别的
pub
: 用于标记整个模块及其内容对外部的可见性。// src/lib.rs pub mod my_module { pub fn public_function() { // 公共函数 } fn private_function() { // 私有函数 } }
结构体、枚举和 trait 的
pub
: 用于标记结构体、枚举和 trait 可以在其他模块中使用。pub struct PublicStruct { // 公共结构体 } impl PublicStruct { pub fn new() -> Self { // 公共方法 PublicStruct {} } }
函数级别的
pub
: 用于标记函数可以在其他模块中调用。pub fn public_function() { // 公共函数 }
3. pub(crate)
和 pub(in path)
除了全局的 pub
,Rust 还支持限制可见性到模块本身或其父级模块(pub(crate)
),或者限制到特定的路径(pub(in path)
)。
pub(crate)
: 限制可见性到当前 crate 内部。mod my_module { pub(crate) fn internal_function() { // 只在当前 crate 内部可见的函数 } }
pub(in path)
: 限制可见性到指定路径中的模块。
使用 pub(in path)
语法定义的函数只在给定的路径中可见。 path
必须是父模块(parent module)或祖先模块(ancestor module)
仅限在同一个crate 中
mod outer {
pub mod inner {
pub(in crate::outer) fn restricted_function() {
// 只在 crate::outer 模块内可见的函数
}
}
}
4. pub use
重导出
pub use
允许将一个项重新导出到当前模块的公共接口,这在创建模块的公共 API 时非常有用。
mod private_module {
pub fn internal_function() {
// 内部函数
}
}
pub mod public_module {
pub use private_module::internal_function;
pub fn public_function() {
// 公共函数
}
}
7. pub(crate)
的详细使用
pub(crate)
是 Rust 中一种特殊的可见性修饰符,用于限制项(函数、类型、模块等)只在当前 crate 内部可见。这种限制非常有用,特别是在需要隐藏特定实现细节但又需要模块内部共享的情况下。
7.1. 在模块中使用 pub(crate)
在模块中使用 pub(crate)
可以确保其内部的项只能在当前 crate 中的其他模块中使用,而不会暴露给外部 crate。
// src/lib.rs
pub mod my_module {
pub(crate) fn internal_function() {
// 只在当前 crate 内部可见的函数
}
}
// 在其他模块中使用
mod another_module {
use crate::my_module::internal_function;
pub fn call_internal_function() {
internal_function();
}
}
7.2. pub(crate)
和 pub
的比较
pub
: 公共的,可以被当前 crate 内外的所有模块访问。pub(crate)
: 只有当前 crate 内部的所有模块可以访问,外部 crate 禁止访问。
通过使用 pub(crate)
,你可以在保持模块私有性的同时,允许 crate 内部的不同模块共享实现细节,这对于确保代码的内聚性和封装性非常重要。
7.3. pub(crate)
示例
// src/lib.rs
pub mod data {
pub(crate) struct Database {
// 数据库结构体,只有当前 crate 内部可见
}
impl Database {
pub(crate) fn new() -> Self {
// 创建数据库实例,只有当前 crate 内部可见
Database {}
}
pub fn query(&self, query: &str) {
// 查询方法,可以在当前 crate 内外的所有模块中使用
}
}
}
// 在其他模块中使用
mod services {
use crate::data::Database;
pub fn perform_query() {
let db = Database::new();
db.query("SELECT * FROM users");
}
}
在上面的示例中,Database
结构体和其 new
方法使用了 pub(crate)
,这意味着只有定义了 Database
的 crate 内部的所有模块可以创建 Database
实例和调用 new
方法,而 query
方法由于是 pub
,所以可以在当前 crate 内外的所有模块中使用。