Confused about modules

I've tried a few things now but I'm rather confused how to break up some of my code...
Basically I want to have 3 types, and they all depend on the previous ones in a chain.

LabelData ->Node -> SuffixTree

Now I was thinking that I could just do the following in my file system

src
* types
* * label_data.rs
* * node.rs
* * suffix_tree.rs
* lib.rs

label_data.rs does not require any other modules, so no mod's in that.
In node.rs I was thinking I could just do

mod label_data;

[...]

And in suffix_tree.rs

mod label_data;
mod node;

[...]

However I am getting plenty of errors trying this.. I cannot use any mod in lib.rs at all. I read that I could make a types.rs in the same folder as lib.rs so I also tried that.
types.rs is just the following...

pub mod label_data;
pub mod node;
pub mod suffix_tree;

And that works for importing things in lib.rs now as

mod types;
use types::suffix_tree::SuffixTree;

[...]

But I now get errors in the individual files about node.rs not being able to find mod label_data and the suffix_tree.rs cannot find either of them as well.

Coming from a C# background (harsh I know), the import and namespaces just seem to "work" but I think I am not understanding how these modules and their visibility works. So I am asking for help in clarifying this, and maybe how to sort all this Separation of Concerns out into smaller and cleaner files for this particular example.

mod is for creating a module. You only need to use mod once per module.

use is for importing a module. You use use each time you need to bring the module into scope.

So let's start with the mods. In lib.rs:

mod types;

In types.rs (or types/mod.rs, which does the same thing):

pub mod label_data;
pub mod node;
pub mod suffix_tree;

We've written mod once for each module, so we won't write mod again. Now let's use the modules where we need them. Here's the part you already figured out, in lib.rs:

use types::suffix_tree::SuffixTree;

In node.rs, we need to use the module named label_data, but it is in types, which is not a submodule of the current module, so we need to give a path so the compiler knows where to look. super is an alias for the parent of the current module, which in this case is types.

use super::label_data;

And in suffix_tree.rs, we need to use the module node, so we can do the same thing. Alternatively, you can use an absolute path that starts from the crate root:

use crate::types::node; // same as super::node
2 Likes

mod does not import a modul, it declares or defines one. Hence, you shouldn't write mod foo; more than once. If you want to import a module, you'll need use foo; instead.

That makes a lot of sense. The super and crate paths was definitely what I wasn't getting. Thanks for taking the time to spell it out for me :grin:

No problem! You're certainly not the only one to be caught up by it. Many people have trouble with the module system at first because it's not quite what they're used to. But I think once you get the hang of it, it does make a lot of sense.

The types.rs file does seem a little superfluous doesn't it?

I recommend reading Clear Explanation of Rust's Module System to help wrap your head around it.

1 Like

Well, you need to declare each module somewhere, but you can always inline a module into the parent:

// in lib.rs
mod types {
    pub mod suffix_tree;
    pub mod node;
    pub mod label_data;
}
1 Like