我正在做一个Rust模块,它有一个很小的外部接口,但是它的内部实现是大而复杂的。
是否有一个合理的方法来避免有一个巨大的文件与所有的模块代码,同时仍然暴露一个小的接口给外部模块消费者?
老实说,Rust不允许你在同一个模块中使用多个文件,就像Go允许包目录一样。Rust模块是否定义在目录中并不重要,它仍然需要一个单独的文件。
这样,为了拆分代码,你就不得不使用子模块来处理你想要拆分的子类型或实现细节。我理解这对于编译后的代码来说应该无关紧要,因为模块组织的所有开销都被删除了。
但是有一个设计问题,如果我把东西分成模块,那些需要导出的东西,这样我就可以从我的其他模块中使用它们…但是那些"出口的内部"也可以被外部消费者使用,对吗?有没有一种方法可以避免暴露这些内部接口?
但是有一个设计问题,如果我把东西分成模块,那些需要导出的东西,这样我就可以从我的其他模块中使用它们…但是那些"出口的内部"也可以被外部消费者使用,对吗?
不,他们不能。
在子模块中将一个符号设为public,只会使它对它的直接父模块可用。然后,父模块必须通过pub use
重新导出该符号,以使可见性"冒出"。
mod foo {
mod bar {
pub fn visible_in_foo() {}
pub fn visible_in_root() {}
fn private() {}
}
// Re-export to make visible at the next outer level
pub use bar::visible_in_root;
pub fn foo() {
// We are in the immediate parent, so both `pub` functions are visible
bar::visible_in_foo();
bar::visible_in_root();
// bar::private(); - Won't compile
}
}
// Make it public to consumers of the library, aka. external API
pub use foo::foo;
fn main() {
// Notice that it's just `foo`. Not `foo::bar` or `bar`.
// Re-exporting makes the symbol a part of module `foo`.
foo::visible_in_root();
// foo::visible_in_foo(); - Won't compile
// `foo::foo` does have access to the inner module, though,
// so we can call `foo::bar::visible_in_foo` indirectly here.
foo::foo();
}
另外,你可以将符号标记为pub(crate)
,它的工作原理类似于pub
,除了它阻止符号在crate之外成为公共的,即使它被所有的父模块重新导出。
进一步阅读:
- Rust编程语言-定义模块来控制作用域和隐私
- Rust参考-可见性和隐私