如何在一个库中拥有一个公共特质和一个 pub(crate) 方法?

3
假设我有一个库中包含以下的特性:
pub trait Foo {
    fn public_op(&self);
    fn internal_op(&self);
}

然后,这个特性被实现于此库中的一些结构体中:

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) {}
}

这个库中有一个公共函数可以接收特性类型:

pub fn process(obj: &dyn Foo) {
    obj.public_op();
    obj.internal_op();
}

问题在于,由于库中的Foo特质是公开的,因此方法internal_op也是公开的...但实际上它应该具有pub(crate)可见性,因为它必须仅在库内部使用。
据我所知,特质的所有方法都是公开的,那么我该如何重新设计解决这个问题呢?

public_opinternal_op之间的关系是什么--一个是通过另一个实现的吗?例如,某人是否可以仅通过实现public_op来为外部类型实现Foo?或者Foo根本无法在外部实现? - trent
@trentcl public_opinternal_op 之间没有关系,除了传递给 process 的对象必须同时实现两者。 - rodrigocfd
1个回答

4

您可以将 Foo 拆分为两个特征,一个公共的和一个私有的。

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

pub(crate) mod private {
    pub trait Foo {
        fn internal_op(&self);
    }
}

然后按照以下方式在您的库创建中实现它们:

pub struct One {}

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

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

然后,在库外部使用它的方式如下:

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

这确实意味着,你的库的用户无法将 Foo 实现为 Foo,因为现在它有效地成为了一个“密封特质”

请参阅杰克·伦恩(Jack Wrenn)的博客文章,了解此问题和替代方法的讨论。 Rust playground 链接

2
不错。这里的超特质关系可能是 OP 想要的,但这并不是你能够解释它的唯一方式 -- 例如,你可以让 private::Foo 要求 crate::Foo,这将允许外部代码实现 crate::Foo,但你必须在 process 的 API 中使用 private::Foo这篇博客文章包含了一些更多建立在相同公共私有技巧上的想法。 - trent
1
哈哈!当你在评论时,我刚刚链接了那篇博客文章并解决了这个问题! - willjcroz
我刚刚尝试了所描述的“sealed trait”。它禁止用户实现“private trait”,但方法仍然存在,对最终用户可见。我想要的是防止方法被调用,而不仅仅是防止它们在用户结构中被实现。 - rodrigocfd
@rodrigocfd 这确实会防止调用 internal_op 方法(这就是整个目的!)。尝试在我的答案末尾使用游乐场链接,并取消注释 main() 中的 one.internal_op(); 调用。Rustc 将响应错误:error[E0599]: no method named `internal_op` found for struct `One` in the current scope.也许你的 IDE 会因为这个“技巧”而感到困惑,并为隐藏方法提供自动完成建议,我知道 intellij-rust 会这样做。 - willjcroz

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