I'm learning about Rust, and trying to figure out the visibility rules for modules. I have the following code:
fn x() -> u8 {
5
}
struct Person {
name: String,
}
mod example {
use super::{x, Person};
pub fn foo(person: &Person) {
println!("{}", x());
println!("Person with name: {}", person.name);
}
}
fn main() {
let person = Person{name: String::from("PersonName")};
example::foo(&person);
}
Which throws the following error:
Compiling playground v0.0.1 (/playground)
error[E0446]: private type `Person` in public interface
--> src/main.rs:12:5
|
5 | struct Person {
| ------------- `Person` declared as private
...
12 | pub fn foo(person: &Person) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
For more information about this error, try `rustc --explain E0446`.
error: could not compile `playground` due to previous error
From my understanding, children submodules should have visibility to the symbols from the parent module.
I'm not sure why I need to mark Person
as public.
If I mark Person
as public the code executes, but my next question is, why I don't have to mark the x()
function as public also, as it is used at the same place with the Person
instance.
Inside the module example
it's not known that the module is only visible to super
it also might have been reexported somewhere completely different in main.rs
:
pub mod completely_diffrent {
pub use super::example;
}
which would be difficult or even impossible to track.
A solution other than making Person
public is to mark the function public only to super
:
mod example {
use super::{x, Person};
pub(super) fn foo(person: &Person) {
println!("{}", x());
println!("Person with name: {}", person.name);
}
}
Which avoids all those pitfalls and thus compiles as you can see on the Playground
For why you'd have to mark Person
as public but not x
the reason is that Person
appears in the signature of foo
: fn(&Person)
while x
does not.