this is my src folder structure
src/
|-- main.rs
|-- problems
| |-- mod.rs
| |-- p1.rs
| `-- p2.rs
`-- utilities.rs
I have my utilities.rs file containing 2 functions I use in p1.rs and p2.rs. In both p1.rs and p2.rs are the lines
#[path = "../utilities.rs"]
mod utilities;
that, as far as I understand, allow me to use the functions defined in the utilities.rs
The two functions defined in utilities.rs are
pub fn get_lines(num: &str) -> Vec<String> {...}
pub fn split(s: &String, separator: &str) -> Vec<String> {...}
In p2.rs I use them both, but in p1.rs I only use get_lines. This causes cargo to warn me of a "never used" function, it being split, when I run or build. But the function is used, and not only in functions that are never called, so I don't understand why cargo is warning me. It would seem I have to use every single module function in every single file where I include a self-made module, because if I do call split in p1.rs then the warning disappears. What do I not understand?
To be clearer, the problem is that when I cargo run I get the following
warning: function is never used: `split`
--> src/problems/../utilities.rs:23:8
|
23 | pub fn split(s: &String, separator: &str) -> Vec<String> {
| ^^^^^
|
= note: `#[warn(dead_code)]` on by default
You should generally never use the #[path] attribute in ordinary situations, because it lets you make this mistake.
The key to understanding Rust modules is that mod defines a module and its contents. Every mod item is a different module from any others. Therefore, if you write mod twice in such a way that both refer to the same file, that file gets compiled twice, producing two copies of what's defined in that file. That's why you're getting dead_code warnings — you've defined two different functions, problems::p1::utilities::split() and problems::p2::utilities::split(), and one of them isn't used.
As a general rule, in projects with simple structure, there should be only one mod item for any module source file in your project. In this case, the natural place to locate that mod item is in main.rs, and it should be:
mod utilities;
Then, you can refer to this module in your p1.rs or p2.rs as:
use crate::utilities;
On the other hand, maybe the utilities are more associated with the problems module only. In that case, you would
place the file at src/problems/utilities.rs,
write mod utilities; in src/problems/mod.rs, and
refer to the utilities in p1 and p2 as either use super::utilities; (relative path) or use crate::problems::utilities; (absolute path).
In general, the procedure for introducing a new module is:
Pick a module to be the parent module of your module. (Don't think in directories and files, think in modules.)
Write mod my_module_name; in that parent module.
Put the file where it needs to be, given that. (If you try to compile the program at this point, the compiler will tell you what file is missing; or if you use rust-analyzer in an IDE you can ask it to create the file.)
Everywhere you want to use that module, refer to it by the appropriate absolute or relative path according to where its mod is; and use use if you want to make a convenient short alias for its path.
You could use a crate import instead of the path modifier (which I cannot prove, but is probably the guilty one), in both p1 and p2:
use crate::utilities;
Related
So I want to have some modules defined in lib.rs but not make them public but only available for use within the project.
in my lib.rs, if I have the definition as this:
pub mod args;
in my main.rs, I can use the args modules this way:
use my_lib::args::Cli;
where my_lib is defined in Cargo.tml as
[lib]
name = "my_lib"
path = "src/lib.rs"
but I don't want pub mod args;. I tried changing to pub(crate) mod args; but this leads to compilation error that the args module cannot be found.
How do I make a module like args defined in lib.rs available without have to give it the most permissive visibility?
Since Rust separates the library lib.rs and binary main.rs into separate crates there is no simple way to include things that are in lib.rs and not pub from main.rs.
I suggest you follow the way of big crates (serde comes to mind) and add a pub mod __private; which conveys the meaning. You can additionaly annotate it with #[doc(hidden)] to hide it from the documentation making it even more obvious.
Suppose I have this file hierarchy in a Rust package:
src/...
src/m1/mod.rs
src/m1/path/m2.rs
What would be the practical difference between having the line:
pub mod path::m2;
in my file m1/mod.rs, versus having the line:
pub use path::m2;
Trying to refresh my understanding of Rust after a time away, so this isn't my first learning cycle. (Of course, for other readers it may be.) I'm saying this because I'm not asking for a general explanation of the differences between use and mod. My unclarity is specific to the two directives above. It seems like they would both serve to make the module in file src/m1/path/m2.rs available to the module m1 and to anything else that imported it (because of the pub prefix on both directives). Is that right? Would these be perfect aliases, or would there be some differences? Is either idiom preferable to the other?
mod foo; is akin to copying and pasting a module into the current scope. That is, if the current scope can find module foo at its own "top level" — basically, if there's a file foo.rs or a folder foo in the same directory — then mod foo; basically gets transformed into mod foo { /* contents of foo */ }. Note that the syntax for mod requires that the thing after mod be an identifier, not an arbitrary path (so mod path::m2; would be illegal). I can only assume that modules that could be brought into scope aren't automatically brought into scope in order to limit the amount of work the compiler has to do when resolving names.
Meanwhile, once a container of items — whether that be a module, type, trait, etc — has been made available in the current scope, shortcuts to its items can be created with use path::to::item. If containers of items were ordinary variables, this would be akin to something like let item = path.to.item, if that were legal.
I'll edit this answer later to give a fuller explanation. But, with help from the comments and other answer posted here, plus some experimentation, I think I've come to a better understanding of these directives. There may be circumstances where one could use either pub use or pub mod, though they'd be contrived and in any case where both could work one should prefer the former (see third point below). The key differences are:
pub use is followed by a path (a bare identifier m2 would be the same as self::m2). pub mod is only followed by an identifier.
pub mod m2; in main.rs or lib.rs would include the contents of file ./m2.rs (or ./m2/mod.rs). If the line pub mod m2; is instead in a file path/m1.rs (or path/m1/mod.rs) then the included file would instead be path/m1/m2.rs (or path/m1/m2/mod.rs).
(You could include a module from another location using mod m2 { include!("path/m2.rs") } but this isn't idiomatic. I've also seen some attribute tricks that affect the location of the loaded module. But generally things work as described in the previous paragraph.)
The use directive doesn't request/order the compilation of any additional files. A mod directive is needed to do that.
(In fact the additional files aren't compiled separately, but merged into the source file where the mod directive occurs. Only the files that are crate roots (plus whatever is merged into them) get compiled.)
If one file in your crate had a pub mod m2; line, then another file could conceivably have a choice of also using pub mod or pub use. Subject to the constraints imposed by point 1 above.
But if you were in such circumstances, you wouldn't want to use the mod directive, as that would merge the relevant code into your source tree a second time. Perhaps the compiler might eventually undo the duplication, but what would you gain by hoping for that?
There's also this statement from the "Separating Modules into Different Files" chapter in the book:
Note that you only need to load the contents of a file using a mod declaration once somewhere in your module tree. Once the compiler knows the file is part of the project (and knows where in the module tree the code resides because of where you’ve put the mod statement), other files in your project should refer to the code in that file using a path to where it was declared...
For example, have module within /xyz/ sub-directory. Inside the directory are two files, mod.rs and network.rs say.
Why do mod.rs and network.rs have the same function names, but different code within the functions? Is there any reason for this? I thought mod.rs was just basically a defintions file to declare a module, and specify which other .rs files within the sub-directory should be treated as their own creates / modules.
Any help?
It sounds like you are referring to a design decision made by a specific crate. You are correct in assuming there is no special consideration given by the compiler to function/type/ident names in separate files/modules.
That being said it seems likely that what you are referring to might be using conditional compilation. Conditional compilation lets the compiler decide if a given piece of code is compiled or not. You will usually see this used to handle which implementation of a function is used when compiling code on different operating systems since it is often it too inefficient or simply impossible to check at runtime. Some library authors might also decide to add an implementation that it can fallback to instead of throwing a hard error.
Here is a quick example of why xyz might want to have 3 different implementations of foobar.
// xyz/mod.rs
mod windows;
mod unix;
// If this crate is compiled on windows re-export the contents of windows.rs
#[cfg(windows)]
pub use windows::*;
// If this crate is compiled on unix/linux re-export the contents of unix.rs
#[cfg(unix)]
pub use unix::*;
// If not on either windows or unix provide a default implementation to use instead
#[cfg(not(any(windows, unix)))]
pub fn foobar() -> i32 {
panic!("This function is unsupported on the current os")
}
I'm am trying to re-export a submodule from another file from a parent module.
Give this file structure,
src/
- lib.rs
- module/
-- mod.rs
-- submodule/
--- mod.rs
...can this be accomplished in a single line?
// mod.rs
mod submodule;
pub use submodule::*;
// something like pub use mod submodule::*;
If I understand correctly, you're asking if the mod and the use can be combined into a single line.
No, there is no allowance for combining a mod with a use. The right way to think about mod is that it defines where the module is located in the module hierarchy. The fact that it also brings the module name into the namespace of the current module, as if you had written use some_module;, is essentially a part of that, since it would be pointless to ever write mod some_module without making it visible in its parent.
If you want to also make additional names available, there is no special syntax for combining it with a mod; you have to use use.
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?
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.