Reputation: 1730
What is the exact set of rules that rust uses to look up a module from a file?
Every explanation I have found online about modules says, "this is the purpose of modules, here is an example of one, ..." None give the complete, comprehensive, 100% accurate explanation for how rust looks up modules. Even the rust reference doesn't tell you whether both the crate root and the importing file need to declare mod
! There is no simple ruleset I can use to tell whether it will work.
I'm looking for something I can follow, like:
::
like subdir::subdir::name
name.rs
in the same directory and name/mod.rs
name.rs
and a name/mod.rs
.Upvotes: 2
Views: 912
Reputation: 15094
This is best explained starting from inline modules. Modules are arranged into a hierarchy from the crate root. Every crate, after some desugaring, looks something like this:
// root
pub mod a {
pub mod b {
pub const X: u8 = 1;
}
}
mod foo {
}
Referring to an item in the tree is pretty simple:
::
goes "down" a levelsuper::
goes "up" a levelcrate::
goes to the root levelExamples for referring to X
:
a::b::X
from the crate rootcrate::a::b::X
from anywhere in the cratesuper::a::b::X
from within module foo
b::X
from within module a
mod foo;
is really just syntax sugar for either of the following:
#[path = "foo.rs"]
mod foo;
// or
#[path = "foo/mod.rs"]
mod foo;
Which further desugar to:
mod foo {
include!("foo.rs");
}
// or
mod foo {
include!("foo/mod.rs");
}
If foo.rs
(or foo/mod.rs
) contains a mod bar;
then the whole tree would look like:
mod foo {
mod bar {
// contents of `bar.rs` (or `foo/bar/mod.rs`)
}
// remaining contents of `foo.rs`
}
Please note that the usage of mod.rs
, while still supported, is discouraged. Instead, it's recommended to use foo.rs
for crate::foo
and place any submodules of foo
in the foo/
directory.
If both src/foo/mod.rs
and src/foo.rs
exist, the compiler will throw the following error:
error[E0761]: file for module `foo` found at both "src\foo.rs" and "src\foo\mod.rs"
--> src\main.rs:1:1
|
1 | mod foo;
| ^^^^^^^^
|
= help: delete or rename one of them to remove the ambiguity
crate::
just always corresponds to the root module of the crate being compiled at the time. If your crate is sufficiently complex or doesn't follow convention, then certain crate::...
item paths can refer to different things in different files. But confusion is easily avoidable by following conventions.
Here's the list of conventions I would use to avoid confusion:
#[path]
attributessrc/foo.rs
instead of src/foo/mod.rs
src
Cargo.toml
, use defaults where possibleUpvotes: 6