如何在库中使用 pub(crate) 方法拥有公共特征?

Rod*_*igo 4 visibility traits rust

假设我在图书馆中有以下特征:

pub trait Foo {
    fn public_op(&self);
    fn internal_op(&self);
}
Run Code Online (Sandbox Code Playgroud)

然后针对该库中的一堆结构实现此特征:

pub struct One {}

impl Foo for One {
    fn public_op(&self) {}
    fn internal_op(&self) {}
}

pub struct Two {}

impl Foo for Two {
    fn public_op(&self) {}
    fn internal_op(&self) {}
}
Run Code Online (Sandbox Code Playgroud)

这个库中有一个接收特征类型的公共函数:

pub fn process(obj: &dyn Foo) {
    obj.public_op();
    obj.internal_op();
}
Run Code Online (Sandbox Code Playgroud)

问题是,由于Foo特征在库中是公共的,因此该方法internal_op也是公共的......但实际上它应该具有pub(crate)可见性,因为它必须仅在库内部使用。

据我所知,一个特质的所有方法都是公共的,那么我该如何重新设计这个问题呢?

wil*_*roz 5

您可以分为Foo两种特征,一种是公共的,一种是私人的。

pub trait Foo: private::Foo {
    fn public_op(&self);
}

pub(crate) mod private {
    pub trait Foo {
        fn internal_op(&self);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将它们都实现在您的库箱中,如下所示:

pub struct One {}

impl Foo for One {
    fn public_op(&self) {}
}

impl private::Foo for One {
    fn internal_op(&self) {}
}
Run Code Online (Sandbox Code Playgroud)

然后从库箱外部使用将如下所示:

fn main() {
   let one = One {};
   one.public_op(); // works
   process(&one); // works
   
   //one.internal_op(); // error[E0599]: no method named `internal_op`...
}
Run Code Online (Sandbox Code Playgroud)

这确实意味着您的库的用户不可能实现现在Foo实际上Foo“密封特征”的功能

有关此方法和替代方法的讨论,请参阅 Jack Wrenn 的博客文章。

Rust 游乐场链接

  • 好的。这里的 supertrait 关系可能是 OP 想要的,但这不是你解释它的唯一方法——例如,你可以让 `private::Foo` 需要 `crate::Foo` 来代替,这将允许外部代码实现 `crate::Foo`,但是你必须在 `process` 的 API 中使用 `private::Foo`。[这篇博文](https://jack.wrernn.fyi/blog/private-trait-methods/) 包含更多基于相同的公开私下技巧的想法。 (2认同)