Using structs that reference each other is common in a single file, but when I separate the structs into two files, I get an error.
mod_1.rs
mod mod_2;
use mod_2::Haha;
pub struct Hehe {
obj: Haha,
}
fn main() {
Hehe(Haha);
}
mod_2.rs
mod mod_1;
use mod_1::Hehe;
pub struct Haha {
obj: Hehe,
}
fn main() {
Haha(Hehe);
}
This will produce an error. When compiling the mod_1.rs
:
error: cannot declare a new module at this location
--> mod_2.rs:1:5
|
1 | mod mod_1;
| ^^^^^
|
note: maybe move this module `mod_2` to its own directory via `mod_2/mod.rs`
--> mod_2.rs:1:5
|
1 | mod mod_1;
| ^^^^^
note: ... or maybe `use` the module `mod_1` instead of possibly redeclaring it
--> mod_2.rs:1:5
|
1 | mod mod_1;
| ^^^^^
When compiling the mod_2.rs
:
error: cannot declare a new module at this location
--> mod_1.rs:1:5
|
1 | mod mod_2;
| ^^^^^
|
note: maybe move this module `mod_1` to its own directory via `mod_1/mod.rs`
--> mod_1.rs:1:5
|
1 | mod mod_2;
| ^^^^^
note: ... or maybe `use` the module `mod_2` instead of possibly redeclaring it
--> mod_1.rs:1:5
|
1 | mod mod_2;
| ^^^^^
In mod_1.rs
I use something from mod_2.rs
and in mod_2.rs
, I use mod_1.rs
's thing, so I'd like to find a way to get rid of the cycle reference module problem.
Trying to get Rust to load files is a similar but different problem.
This is a common misunderstanding of Rust's module system. Basically, there are two steps:
You have to build a module-tree. This implies that there are not cycles in this module-tree and there is a clear parent-child relationship between nodes. This step is simply to tell Rust what files to load and has nothing to do with usage of certain symbols in different modules.
You can now reference each symbol in your module tree by its path (where each module and the final symbol name is separated by
::
, for examplestd::io::read
). In order to avoid writing the full path every time, you can useuse
declarations to refer to specific symbols by their simple name.You can read a bit more on that in the Rust book chapter.
And again, to avoid confusion: in order to use a symbol from a module, you don't necessarily have to write
mod my_module;
in your module! For each non-root module of your project there is only one line in your entire project sayingmod said_module;
(the root module does not have such a line at all). Only once!About your example: you first compiled
mod_1.rs
viarustc mod_1.rs
. This means thatmod_1
is the root module in your case. As explained above, the root module doesn't need to be declared viamod
at all, but all other modules need to be declared exactly once. This means themod mod_2;
inmod_1.rs
is completely correct, but themod mod_1;
inmod_2.rs
is incorrect. The compiler even suggest the right thing to do:You are already
use
ing it, so you can just remove the linemod mod_1;
and solve this error.However, I think you are still thinking incorrectly about the module system. As mentioned above you first need to design a more or less fixed module tree which implies that you have one fixed root module. Whatever you pass to
rustc
is the root module and it doesn't make sense to use different modules as root module. In your project there should be one fixed root module. This could bemod_1
as explained above. But it's usually more idiomatic to call itlib
for libraries andmain
for executables.So again: first, draw your module tree on a piece of paper. Consider this fixed for the moment and then you can create the files and
mod
declarations appropriately.Last thing: even when fixing the module system, your example won't work, because
Haha
andHehe
are types with infinite size. Fields of structs are directly put into the memory layout of the struct (without boxing them like in Java!). Thus you can't have cycles in struct definitions, except if you manually add a layer of indirection, like boxing the fields. Please read this excellent explanation on this issue.