Masked Man
Masked Man

Reputation: 552

How to have multiple files with one module?

I don't understand why we have only one file per module.

// main.rs

mod dog; // Find dog in dog.rs or dog/mod.rs
fn main() {
    dog::sonic_bark();
}

When dog grows larger and has lots of functions, it's not good to have all of them in one file.

How I can separate them without using

dog::leg::walk();
dog::head::nose::smell();
dog::tail::iron_tail();
dog::mouth::sonic_bark();

I want to just use dog::sonic_bark();

Upvotes: 13

Views: 4842

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 300349

You cannot.

You can have more modules than files (the typical examples being mod tests nested in the file), but not the reverse.


However, this does not matter because you can use encapsulation + re-export.

The default when declaring a submodule with mod xxx; is that xxx is private: no user of the current module will know that it depends on xxx.

Combine this with selecting re-exporting symbols:

pub use self::leg::walk;
pub use self::head::nose::smell;
pub use self::tail::iron_tail;
pub use self::mouth::sonic_bark;

And you can call those directly: dog::walk(), dog::smell(), ...

Therefore, private imports and public re-exports help you have a hidden internal hierarchy while exposing a flat public interface.


Complete example:

mod dog {
    pub use self::head::nose::smell;
    pub use self::leg::walk;
    pub use self::mouth::sonic_bark;
    pub use self::tail::iron_tail;

    mod leg {
        pub fn walk() {}
    }

    mod head {
        pub mod nose {
            pub fn smell() {}
        }
    }

    mod tail {
        pub fn iron_tail() {}
    }

    mod mouth {
        pub fn sonic_bark() {}
    }
}

fn main() {
    dog::sonic_bark();
}

Upvotes: 16

Shepmaster
Shepmaster

Reputation: 432079

It is possible, but you should absolutely not do this because it's unidiomatic, will probably break various tools and IDEs, and is just generally confusing. Please don't read this except for educational purposes.


The trick is to use include! to directly import source code.

Filesystem

do-not-do-this
├── Cargo.toml
├── src
│   ├── dog-head.rs
│   ├── dog-tail.rs
│   ├── dog.rs
│   └── main.rs

src/main.rs

mod dog;

fn main() {
    dog::bark();
    dog::wag();
}

src/dog.rs

include!("dog-head.rs");
include!("dog-tail.rs");

src/dog-head.rs

pub fn bark() {
    eprintln!("Woof");
}

src/dog-tail.rs

pub fn wag() {
    eprintln!("Swish");
}

Upvotes: 8

Related Questions