Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to split an impl into different modules?

Tags:

rust

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.

like image 254
Attila Mika Avatar asked Aug 09 '14 14:08

Attila Mika


People also ask

What is impl in Rust?

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.

What is a module in Rust?

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.


1 Answers

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.

  • #9052
  • #9584
  • #12729

And thus there is an RFC for (temporarily) removing this functionality.

like image 153
huon Avatar answered Sep 25 '22 00:09

huon