Private inner module returning private item gives “private type in public interface” error

坚强是说给别人听的谎言 提交于 2021-01-28 09:12:03

问题


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.

回答1:


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.



来源:https://stackoverflow.com/questions/50753923/private-inner-module-returning-private-item-gives-private-type-in-public-interf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!