I am trying to split an impl
into different modules.
The items in the child impl
blocks should be accessible by the parent impl
, but not publicly accessible by the users of the struct/enum that is implemented.
Here is my attempt:
mod foo {
pub struct Foo {
field: String
}
impl Foo {
pub fn new() -> Foo {
Foo { field: "Joe".to_string() }
}
pub fn pubfn(&self) {
self.my_impl();
}
}
// Ideally, this should be in a separate file
mod foo_impl_details {
impl super::Foo {
// If I make this `pub`, it will be publicly visible to
// users of `Foo`, not just the impl block in `super`
fn my_impl(&self) {
println!("{} reporting for duty!", self.field);
}
}
}
}
fn main() {
let foo = foo::Foo::new();
foo.pubfn();
}
This results in a compile error:
<anon>:11:13: 11:27 error: method `my_impl` is private
<anon>:11 self.my_impl();
^~~~~~~~~~~~~~
If I mark the my_impl
method with pub
, it will be publicly accessible not only to the parent module's impl
block, but also to the outside users of foo::Foo
, which is not what I want.
The impl keyword is primarily used to define implementations on types. Inherent implementations are standalone, while trait implementations are used to implement traits for types, or other traits. Functions and consts can both be defined in an implementation.
Rust provides a powerful module system that can be used to hierarchically split code in logical units (modules), and manage visibility (public/private) between them. A module is a collection of items: functions, structs, traits, impl blocks, and even other modules.
This seems somewhat like expected behaviour: the my_impl
method is private and thus only visible inside the module in which it is declared. On the other hand, it's strange that the pub
version is visible everywhere, despite foo_impl_details
being a private module. I filed #16398 about this.
You can separate modules (and thus files, since mod foo { ... }
is the same as mod foo;
with the code in foo.rs
or foo/mod.rs
) out while maintaining privacy by using freestanding functions, e.g.
mod foo {
pub struct Foo {
field: String
}
impl Foo {
pub fn new() -> Foo {
Foo { field: "Joe".to_string() }
}
pub fn pubfn(&self) {
foo_impl_details::my_impl(self);
}
}
mod foo_impl_details {
fn my_impl(x: &super::Foo) {
println!("{} reporting for duty!", x.field);
}
}
}
There's no difference between freestanding functions and methods other than the calling syntax.
Also, there are a variety of issues with writing non-trait impls not adjacent to the type declaration so this behaviour is probably not by-design, e.g.
And thus there is an RFC for (temporarily) removing this functionality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With