如何使一个 Rust crate 中的项在 crate 内部是公共的,但在 crate 外部是私有的?

60
我有一个包含很多代码的箱子,因此我将其拆分成多个文件/模块。但是,一些模块具有内部不安全的东西(例如原始指针),我需要将其公开给不同的模块使用,但我不想向我的包的用户公开。我该怎么做?
我能想到的唯一方法是使我的包只成为一个大模块,但是除了这种看起来有点“hacky”的解决方案之外,我们无法将其拆分为不同的文件。
通常,当我遇到Rust文档中简单示例不足以解释现实世界问题时,我会复制受欢迎的现实世界包(例如git2-rs),但那似乎有效地将所有东西都公开了,包括原始指针。
1个回答

86
为了从库创建一个item,必须至少有一条路径可以到达它,其中每个组件都是公共的。这意味着您只需要将项目放入私有模块下即可使其在 crate 内部公开,但不导出(现在我称之为“内部”,以模仿 C# 术语)。
然而,这种解决方案相当受限制。如果您想要一个包含导出函数和内部函数的模块怎么办?为了导出某些函数,我们需要将模块公开,这意味着该模块中的所有公共项也将被导出。
自从Rust 1.18以来,就有了适用于这种情况的解决方案:pub(restricted)。此功能允许您指定一个项的“公共程度”。语法非常灵活(您可以使一个项对特定模块树可见,而不是整个crate),但如果您想保持简单,pub(crate)将使项目在crate内任何地方都可以访问,但其他crate将无法访问(相当于C#中的internal)。
例如,假设我们想要在一个名为util的模块中导出foo(作为mycrate::util::foo),而bar是内部的,baz是私有的。代码可能如下所示:
pub mod util {
    pub fn foo() {
        unimplemented!()
    }

    pub(crate) fn bar() {
        unimplemented!()
    }

    fn baz() {
        unimplemented!()
    }
}

如果您在1.18版本之前的Rust上卡住了,有一个解决方法,但有点麻烦。它涉及将所有项目定义为私有模块,并仅在仅包含重新导出的公共模块中重新导出希望公开的项目(使用pub use)。以下是上面示例的样子:
pub mod util {
    pub use util_impl::foo;
}

mod util_impl {
    pub fn foo() {
        unimplemented!()
    }

    pub fn bar() {
        unimplemented!()
    }

    fn baz() {
        unimplemented!()
    }
}

这不仅阅读和理解难度大,而且没有覆盖所有使用pub的情况。例如,如何使导出结构体中的某些字段在同一箱中的其他模块中可访问而不必将它们也导出?唯一的选择是公开一个包装器,其具有一个私有字段,其类型为具有公共字段的结构体;如果您想要隐藏来自其他箱的所有字段,则可以正常工作,但是如果您想同时公开一些字段并使同一结构中的其他字段为内部,则无法做到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接