返回私有项目的私有内部模块给出“公共接口中的私有类型".错误 [英] Private inner module returning private item gives "private type in public interface" error

查看:110
本文介绍了返回私有项目的私有内部模块给出“公共接口中的私有类型".错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的示例中,模块 outer 具有私有类型 Private 和私有内部模块 inner . inner 可以访问 Private (因为子模块可以访问其父级的私人物品,即使它们未作为公共停车场停放).

inner 定义一个函数 not_really_public_interface().虽然它被标记为公开,但实际上仅对 outer 可用,因为 inner 本身不是公开的.

outer.rs

  struct私有;mod内部{使用super :: Private;pub fn not_really_public_interface()->私人的 {私人的}} 

该编译没有任何问题.

外部应该能够使用 inner :: not_really_public_interface()获得 Private ,只要确保不导出即可.因此,让我们这样做:

  pub fn main(){让_ = self :: inner :: not_really_public_interface();} 

对吗?

stderr

 错误[E0446]:公共接口中的私有类型私有"->src/outer.rs:4:3|4 |/pub fn not_really_public_interface()->私人的 {5 ||私人的6 ||}|| ___ ^不能泄漏私有类型 

Wat.这对我来说是违反直觉的,原因有几个:

  • 即使前一个代码使用Rust认为泄漏"的接口定义了一个函数,也不会产生任何错误.仅当外部尝试使用此功能时,才会发生错误.
  • 内部唯一可能泄漏" 私有的地方是定义它的模块.

所以我的问题是:

  • 这里到底发生了什么,导致Rust得出该接口的任何部分泄漏的结论?似乎将 Private 视为是在 inner 中定义的.
  • 是否有一个可以说得通的背景?我的第一个想法是,这是编译器中的错误,或者是隐私设计中的疏忽,但我怀疑情况确实如此.
  • 有没有一种方法可以解决此问题而不创建另一个模块?我相信我可以创建一个包装器模块,然后在 outer inner 中公开 Private ,但是我不希望这样做.

解决方案

函数 not_really_public_interface 公开的,因此它可以被 any 使用其他模块.但是 Private 结构只能由您的root和 inner 模块访问.

如果另一个模块导入了 not_really_public_interface ,则会发生泄漏.Rust抱怨这种可能的发生是因为它会在本地报告错误,而不是对所有模块和板条箱中的所有用法都采取整个世界"的观点.最终,这种方法对于人类来说是更可预测的,并且可以使机器推理得更快.

Rust使您可以更精确地控制可见性.如果您告诉它该功能仅对上一级模块( super 模块)可用,则它知道不存在泄漏的可能性:

  mod内部{使用super :: Private;pub(super)fn not_really_public_interface()->私人{私人}} 

您也可以使用 crate 而不是 super 来表示同一包装箱中的任何模块.或者,如果超级模块具有名称,例如 my_mod ,则可以使用 pub(in :: my_mod)专门定位.

In the below example, the module outer has a private type Private and a private inner module inner. inner is able to access Private (because child modules can access their parent's private items, even if they are not parked as public).

inner defines a function not_really_public_interface(). While it is marked as public, it is really only available to outer because inner itself is not public.

outer.rs

struct Private;
mod inner {
  use super::Private;
  pub fn not_really_public_interface() -> Private {
    Private
  }
}

This compiles without any problems.

outer should be able to use inner::not_really_public_interface() to obtain Private, as long as it makes sure not to export it. So let's do that:

pub fn main() {
  let _ = self::inner::not_really_public_interface();
}

Right?

stderr

error[E0446]: private type `Private` in public interface
 --> src/outer.rs:4:3
  |
4 | /   pub fn not_really_public_interface() -> Private {
5 | |     Private
6 | |   }
  | |___^ can't leak private type

Wat. This is counter-intuitive to me for several reasons:

  • The former code produces no error even though it defines a function with an interface Rust considers to "leak". The error only occurs when the outer attempt to use this function.
  • The only place inner could possibly "leak" Private is to the module that defined it.

So my questions are:

  • What exactly is going on here that causes Rust to conclude that any part of this interface leaks? It seems like it treats Private as if it were defined in inner.
  • Is there a context in which this makes perfect sense? My first thought was that this was a bug in the compiler or oversight in the privacy design, but I doubt that's the case.
  • Is there a way to work around this without creating another module? I believe I can create a wrapper module and then just make Private public within outer and inner, but I'd prefer not to do that.

解决方案

The function not_really_public_interface is public so it could be used by any other module. But the Private struct can only be accessed by your root and inner modules.

The leak would occur if another module imported not_really_public_interface. Rust is complaining that this could happen because it reports errors locally, rather than taking a "whole world" view across all usages in all modules and crates. Ultimately, this approach is more predictable for humans to reason about and faster for the machine.

Rust lets you control the visibility more precisely though. If you tell it that the function is only available to the module one level up (the super module) then it knows there is no possibility of a leak:

mod inner {
    use super::Private;

    pub(super) fn not_really_public_interface() -> Private { Private }
}

You could also use crate instead of super, to mean any module in the same crate. Or, if the super module had a name, e.g. my_mod, you could use pub(in ::my_mod) to target it specifically.

这篇关于返回私有项目的私有内部模块给出“公共接口中的私有类型".错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆