If you have a directory structure like this:
src/main.rs
src/module1/blah.rs
src/module1/blah2.rs
src/utils/logging.rs
How do you use functions from other files?
From the Rust tutorial, it sounds like I should be able to do this:
main.rs
mod utils { pub mod logging; }
mod module1 { pub mod blah; }
fn main() {
utils::logging::trace("Logging works");
module1::blah::doit();
}
logging.rs
pub fn trace(msg: &str) {
println!(": {}\n", msg);
}
blah.rs
mod blah2;
pub fn doit() {
blah2::doit();
}
blah2.rs
mod utils { pub mod logging; }
pub fn doit() {
utils::logging::trace("Blah2 invoked");
}
However, this produces an error:
error[E0583]: file not found for module `logging`
--> src/main.rs:1:21
|
1 | mod utils { pub mod logging; }
| ^^^^^^^
|
= help: name the file either logging.rs or logging/mod.rs inside the directory "src/utils"
It appears that importing down the path, i.e. from main
to module1/blah.rs
works, and importing peers, i.e. blah2
from blah
works, but importing from the parent scope doesn't.
If I use the magical #[path]
directive, I can make this work:
blah2.rs
#[path="../utils/logging.rs"]
mod logging;
pub fn doit() {
logging::trace("Blah2 invoked");
}
Do I really have to manually use relative file paths to import something from a parent scope level? Isn't there some better way of doing this in Rust?
In Python, you use from .blah import x
for the local scope, but if you want to access an absolute path you can use from project.namespace.blah import x
.
I'm assuming you want to declare
utils
andutils::logging
at the top level, and just wish to call functions from them insidemodule1::blah::blah2
. The declaration of a module is done withmod
, which inserts it into the AST and defines its canonicalfoo::bar::baz
-style path, and normal interactions with a module (away from the declaration) are done withuse
.The only change I made was the
use utils
line inblah2
. Also see the second half of this answer for more details on howuse
works. The relevant section of The Rust Programming Language is a reasonable reference too, in particular these two subsections:Also, notice that I write it all inline, placing the contents of
foo/bar.rs
inmod foo { mod bar { <contents> } }
directly, changing this tomod foo { mod bar; }
with the relevant file available should be identical.(By the way,
println(": {}\n", msg)
prints two new lines;println!
includes one already (theln
is "line"), eitherprint!(": {}\n", msg)
orprintln!(": {}", msg)
print only one.)To get the exact structure you want:
main.rs
utils/logging.rs
module1/blah.rs
module1/blah2.rs (the only file that requires any changes)
I'm going to answer this question too, for anyone else who finds this and is (like me) totally confused by the difficult-to-comprehend answers.
It boils down to two things I feel are poorly explained in the tutorial:
The
mod blah;
syntax imports a file for the compiler. You must use this on all the files you want to compile.As well as shared libraries, any local module that is defined can be imported into the current scope using
use blah::blah;
.A typical example would be:
In this case, you can have code in
one.rs
fromtwo.rs
by usinguse
:However,
main.rs
will have to be something like:Notice that you can use the
blah/mod.rs
file to somewhat alleviate the awkwardness, by placing a file likeone/mod.rs
, becausemod x;
attemptsx.rs
andx/mod.rs
as loads.You can reduce the awkward file imports at the top of main.rs to:
There's an example project doing this on Github.
It's worth noting that modules are independent of the files the code blocks are contained in; although it would appear the only way to load a file
blah.rs
is to create a module calledblah
, you can use the#[path]
to get around this, if you need to for some reason. Unfortunately, it doesn't appear to support wildcards, aggregating functions from multiple files into a top-level module is rather tedious.If you create a file called
mod.rs
,rustc
will look at it when importing a module. I would suggest that you create the filesrc/utils/mod.rs
, and make its contents look something like this:Then, in
main.rs
, add a statement like this:and call it with
or you could do
Basically, declare your module in the
mod.rs
file, anduse
it in your source files.