9

I want to split a Rust program into multiple files, but the use of mod doesn't see to allow me to reference files in the same directory from files other than main.rs.

For example, if I have main.rs, game.rs, and matrix.rs in the same folder, I can reference structs/functions from game.rs or matrix.rs in main.rs with a mod game; or mod matrix;. I can't, however, reference matrix.rs from game.rs with a statement like mod matrix.

I've looked at several resources and all of them only have modules structures like trees that don't reference each other. Is it possible to use structs/functions from files in each other in Rust, or is that against the rules? If so, why doesn't Rust let you do that?

Rak
  • 133
  • 5
  • Take a look at [this answer](http://stackoverflow.com/a/22597760/994206). This is also covered in [the tutorial](http://static.rust-lang.org/doc/master/book/crates-and-modules.html) – Mokosha Feb 11 '16 at 05:47
  • https://fasterthanli.me/articles/rust-modules-vs-files – Akshay Naik Dec 13 '20 at 06:15

1 Answers1

12

mod is module declaration. This directive declares a module and all of its contents. It just so happens that these contents may be located in another file. So this:

mod game;
mod matrix;

is roughly equivalent to this:

mod game {
    // game.rs contents
}

mod matrix {
    // matrix.rs contents
}

Naturally, since mod is a declaration of a module, you can't do it multiple times for the same module. That is, you can try and write something like

mod game {
    mod matrix;
    ...
}

mod matrix;

but, as you can see, matrix and game::matrix are different modules, and naturally rustc requires different paths to their respective files, if they are external.

use, however, is import declaration. use declarations pull names from other modules for use in the current module. You can use any module and any public items from it any number of times from anywhere this module is accessible.

So, in order to reference matrix from game you need to use it:

// game.rs
use matrix;

Naturally, in order for this to work matrix should be declared with mod in the crate root.

As a side note, I personally think that the simplest way to understand Rust module system is to first forget that modules can be put in different files at all. That is, think as if a crate can only be defined in a single file. In Rust mod directives can have bodies and can nest, so nested mods actually define the module system of a crate:

mod foo {
    mod bax {
        ...
    }
    mod baz {
        ...
    }
}
mod bar {
    mod qux {
        mod zux {
            ...
        }
    }
}

If you only have a single file, you can easily see how mod and use directives would work, and relationship between modules should become clear.

And now you only need to add to the picture the fact that if a module is declared without a body, like in mod name;, its content is loaded either from name.rs or name/mod.rs, whatever is available. However, the full picture does not change in the slightest - these still are nested modules which can always be represented as a single source file with nested mod directives. In fact, cargo rustc -Z unstable-options --pretty=normal will print your crate in this form, after all modules in external source files are assembled into a single document. I suggest running this command on some crates with complex module structure to see how it looks in practice.

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • For me the comprehension of mod is equivalent to a C or Cpp #include directive with some search capabilities to look for either name/mod or name.rs, but I might have missed to subtleties. – Xavier T. Feb 11 '16 at 10:28
  • 4
    @XavierT. the two major differences between C/C++ and Rust is, first, that a compilation unit in Rust is much larger than in C/C++ (a crate, which corresponds to one or more .rs files and one or more modules, vs. an object file, which corresponds to exactly one .c/.cpp file with textually included headers), and second, that in Rust modules actually provide namespaces and encapsulation, which is not true for C and only partially true for C++ (where namespaces do exist, but are not tied to compilation units and do not provide abstraction boundaries). – Vladimir Matveev Feb 11 '16 at 11:40
  • Ah yes, the namespacing is important too ! – Xavier T. Feb 11 '16 at 12:41