This question already has answers here:
Can't understand Rust module system
(1 answer)
Split a module across several files
(7 answers)
How to use one module from another module in a Rust cargo project?
(3 answers)
Closed 2 years ago.
The code below is adapted from "the book" (rustup docs --book), and works as intended in this form - as a single .rs file. I simply want the module to reside in a separate file. I've read Chapter 7 of "the book", "Managing Growing Projects with Packages, Crates, and Modules". I'm just not getting "it". My notion is that the "main" code belongs in main.rs, and the module may need to be in lib.rs, but the exact forms and placements are still a mystery. The chapter often states to run "cargo new/build whatever", but doesn't state from what directory. Likewise, it states that src/main.rs or src/lib.rs should look like such-and-such for a particular example, but it's not clear (without a full path) if one "src" directory is actually in the same location as another.
So, I imagine that's there more than one way to do this, but I'll be happy with a relatively simple answer. In this instance, I only care that the module is accessible from the main() function seen below.
mod guess_mod {
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess{value}
}
pub fn value(&self) -> i32 {
self.value
}
}
}
use guess_mod::Guess;
fn print_guess_value(guess: Guess) {
println!("The value of the guess is {} ", guess.value());
}
fn main() {
let g = Guess::new(18);
print_guess_value(g);
}
You could create the following folder structure within src:
src
├── guess
│ └── mod.rs
└── main.rs
Your guess module could either live in a file called guess.rs or in a folder named guess/ with a mod.rs inside (as in the structure above).
In your mod.rs (or guess.rs) you could put the content of module):
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
In your main.rs you could use it as follows:
// This declaration will look for a file named `guess.rs` or `guess/mod.rs`
mod guess;
use guess::Guess;
fn print_guess_value(guess: Guess) {
println!("The value of the guess is {} ", guess.value());
}
fn main() {
let g = Guess::new(18);
print_guess_value(g);
}
You run cargo from the root of your folder structure (i.e src).
If the rust book is not clear enough for you, perhaps try Rust by Example: https://doc.rust-lang.org/rust-by-example/mod.html
Maybe you are mixing the concepts of crates and modules. They are somewhat related but different.
Crates are separated units of compilation, distribution, versioning, and dependency management.
Modules are pieces of a crate that are logically separated, with visibility barriers maybe also compiled separately, but finally linked together, and bundled into a crate.
If you talk C, you can see crates as libraries and modules as compilation units. Or if you talk C++ or C# you can see modules as namespaces. Except that executables are also crates, but of a different kind.
Now, how do you create them? The easiest are modules. There are three options:
Modules #1
You write the module inline inside other file:
//src/main.rs
mod foo {
pub fn test() {}
}
fn main() {
foo::test();
}
Modules #2
You write the module in a separated file, in the same source directory:
//src/main.rs
mod foo;
fn main() {
foo::test();
}
//src/foo.rs
pub fn test() {}
You can add submodules of foo in a subdirectory named src/foo.
Modules #3
You write the module in a subdirectory, the file must be named mod.rs:
//src/main.rs
mod foo;
fn main() {
foo::test();
}
//src/foo/mod.rs
pub fn test() {}
You can use the subdirectory src/foo to create submodules of foo.
Crates
The easiest way to link a crate is to add it to the [dependencies] section of your Cargo.toml. Then cargo is just magic.
When you create a crate, it may have 0 or 1 libraries and 0 or many binaries. A usual pattern is to create dual Cargo project, that has library and a binary all together. Then you will have a src/main.rs and a src/lib.rs files. The dependency is handled automatically.
//src/main.rs
fn main() {
foo::test();
}
//src/lib.rs
pub fn test() {}
For more complex projects you can split your source into several crates, and handle all them together into a workspace, but I think that is out of scope of this question.
Related
I don't understand why we have only one file per module.
// main.rs
mod dog; // Find dog in dog.rs or dog/mod.rs
fn main() {
dog::sonic_bark();
}
When dog grows larger and has lots of functions, it's not good to have all of them in one file.
How I can separate them without using
dog::leg::walk();
dog::head::nose::smell();
dog::tail::iron_tail();
dog::mouth::sonic_bark();
I want to just use dog::sonic_bark();
You cannot.
You can have more modules than files (the typical examples being mod tests nested in the file), but not the reverse.
However, this does not matter because you can use encapsulation + re-export.
The default when declaring a submodule with mod xxx; is that xxx is private: no user of the current module will know that it depends on xxx.
Combine this with selecting re-exporting symbols:
pub use self::leg::walk;
pub use self::head::nose::smell;
pub use self::tail::iron_tail;
pub use self::mouth::sonic_bark;
And you can call those directly: dog::walk(), dog::smell(), ...
Therefore, private imports and public re-exports help you have a hidden internal hierarchy while exposing a flat public interface.
Complete example:
mod dog {
pub use self::head::nose::smell;
pub use self::leg::walk;
pub use self::mouth::sonic_bark;
pub use self::tail::iron_tail;
mod leg {
pub fn walk() {}
}
mod head {
pub mod nose {
pub fn smell() {}
}
}
mod tail {
pub fn iron_tail() {}
}
mod mouth {
pub fn sonic_bark() {}
}
}
fn main() {
dog::sonic_bark();
}
It is possible, but you should absolutely not do this because it's unidiomatic, will probably break various tools and IDEs, and is just generally confusing. Please don't read this except for educational purposes.
The trick is to use include! to directly import source code.
Filesystem
do-not-do-this
├── Cargo.toml
├── src
│ ├── dog-head.rs
│ ├── dog-tail.rs
│ ├── dog.rs
│ └── main.rs
src/main.rs
mod dog;
fn main() {
dog::bark();
dog::wag();
}
src/dog.rs
include!("dog-head.rs");
include!("dog-tail.rs");
src/dog-head.rs
pub fn bark() {
eprintln!("Woof");
}
src/dog-tail.rs
pub fn wag() {
eprintln!("Swish");
}
(I'm a Rust beginner) I have three files : main.rs, board.rs and case.rs.
I want to include case.rs into board.rs, and board.rs into main.rs, so the board uses the case, and we can access the board in main.
I've successfully added the board into main, but the way I did doesn't seem to work for the second part.
I've tried to encapsulate every file's content into "mod {}" but it doesn't change the problem.
Also I tried every combinations of "mod" and "use".
Every file is in the folder src/, and I'd like them not to move from there if possible.
main.rs
mod board;
fn main() {
let mut b: Board = Board::new();
}
board.rs
mod case;
pub struct Board {
board: [ Case; 9 ]
}
// There is also the impl part of course, let's keep it short
case.rs
pub enum Case { Empty, Full(Player) }
Using VSCode with the Rust plugin, the "case" word on the first line of the board.rs file is underlined red, and it says :
"src/case.rs
file not found for module case
help: name the file either board\case.rs or board\case\mod.rs inside the directory "src""
Why doesn't it search in the current directory?
Your files could look like as follows:
case.rs:
#[derive(Clone, Copy, Debug)]
struct Player;
#[derive(Clone, Copy, Debug)]
pub enum Case {
Empty,
Full(Player)
}
board.rs:
use crate::case::Case;
#[derive(Debug)]
pub struct Board {
board: [ Case; 9 ]
}
impl Board {
pub fn new() -> Self {
Self { board: [Case::Empty; 9] }
}
}
main.rs:
mod case;
mod board;
use crate::board::Board;
fn main() {
println!("{:?}", Board::new());
}
Basically you create a crate (a binary one, because of your main.rs) and that crate can have modules. A module can be a file, or it can be a folder as well (if it happens to have a mod.rs). (And for the sake of completeness, it could also be an inline module without direct relation to the file system.)
Your mod statements (the ones which are indicating files and folders, not the ones which you use to create inline modules) should either be placed at the top level of your crate (e.g. in your main.rs or lib.rs) or at the module levels (in your mod.rs files) depending on the desired structure.
For further info on this, please read the The Rust Programming Language book's relevant chapter: Packages and Crates.
Using the lazy_static library to create a singleton. I am unable to access that singleton in a module in another file. If the module is defined below the main function I can access it fine.
Given a main file such as the following, test_stuff can access gamedata fine:
extern crate gamedata;
#[macro_use]
extern crate lazy_static;
lazy_static! {
pub static ref GAMEDATA: &'static str = "I am a test STrings";
}
fn main() {
println!("Game Data:{}",*GAMEDATA);
let obj = gamedata::readinginstatic::readinginstatic {
structure:"working".to_string()
};
obj.print_static();
}
mod test_stuff {
use ::GAMEDATA;
fn printthing() {
println!("herenow:{}", *GAMEDATA);
}
}
With a lib.rs file such as:
pub mod readinginstatic;
And a module in another file readinginstatic.rs as described below:
use ::GAMEDATA;
pub struct readinginstatic {
pub structure:String,
}
impl readinginstatic {
pub fn print_static(&self) {
println!("In Print static width:{}", *::GAMEDATA);
}
}
I get the error:
not found in the crate root
When trying to import GAMEDATA.
Is it possible to access a lazy_static singleton in another module if it is defined in another file?
To insure I have provided a Minimal, Complete, and Verifiable example here is my whole example code on GitHub: https://github.com/camccar/moduleError
::GAMEDATA refers to some value called GAMEDATA in the crate root of the gamedata crate. However where you defined GAMEDATA was not in that crate, it was in your main.rs file which has gamedata as a dependency.
So what you're trying to do here is reach out of a crate use something from the crate that is depending on you, which I'm not sure but I don't think is allowed.
You could consider inverting this and instead initialising GAMEDATA inside your gamedata crate instead and if you need to use it in main you can just use it normally:
extern crate gamedata;
use gamedata::GAMEDATA;
fn main(){
println!("Game Data:{}", *GAMEDATA);
...
}
Alternatively if GAMEDATA is not something your game data crate should know how to define, you could construct it inside main and pass it to some function in the gamedata crate as a parameter.
I don't understand why we have only one file per module.
// main.rs
mod dog; // Find dog in dog.rs or dog/mod.rs
fn main() {
dog::sonic_bark();
}
When dog grows larger and has lots of functions, it's not good to have all of them in one file.
How I can separate them without using
dog::leg::walk();
dog::head::nose::smell();
dog::tail::iron_tail();
dog::mouth::sonic_bark();
I want to just use dog::sonic_bark();
You cannot.
You can have more modules than files (the typical examples being mod tests nested in the file), but not the reverse.
However, this does not matter because you can use encapsulation + re-export.
The default when declaring a submodule with mod xxx; is that xxx is private: no user of the current module will know that it depends on xxx.
Combine this with selecting re-exporting symbols:
pub use self::leg::walk;
pub use self::head::nose::smell;
pub use self::tail::iron_tail;
pub use self::mouth::sonic_bark;
And you can call those directly: dog::walk(), dog::smell(), ...
Therefore, private imports and public re-exports help you have a hidden internal hierarchy while exposing a flat public interface.
Complete example:
mod dog {
pub use self::head::nose::smell;
pub use self::leg::walk;
pub use self::mouth::sonic_bark;
pub use self::tail::iron_tail;
mod leg {
pub fn walk() {}
}
mod head {
pub mod nose {
pub fn smell() {}
}
}
mod tail {
pub fn iron_tail() {}
}
mod mouth {
pub fn sonic_bark() {}
}
}
fn main() {
dog::sonic_bark();
}
It is possible, but you should absolutely not do this because it's unidiomatic, will probably break various tools and IDEs, and is just generally confusing. Please don't read this except for educational purposes.
The trick is to use include! to directly import source code.
Filesystem
do-not-do-this
├── Cargo.toml
├── src
│ ├── dog-head.rs
│ ├── dog-tail.rs
│ ├── dog.rs
│ └── main.rs
src/main.rs
mod dog;
fn main() {
dog::bark();
dog::wag();
}
src/dog.rs
include!("dog-head.rs");
include!("dog-tail.rs");
src/dog-head.rs
pub fn bark() {
eprintln!("Woof");
}
src/dog-tail.rs
pub fn wag() {
eprintln!("Swish");
}
I have this file hierarchy:
main.rs
protocol/
protocol/mod.rs
protocol/struct.rs
In struct.rs:
pub struct Struct {
members: i8
}
impl Struct {
pub fn new() -> Struct {
Struct { 4 }
}
}
How do I access it as:
mod protocol;
protocol::Struct::new();
// As opposed to:
// protocol::struct::Struct::new();
I've tried various combinations of pub use and mod but admittedly I'm poking at things blindly.
Is it possible to split a struct (and it's impl) into a separate file without having to create a new mod?
The short answer: use pub use Type in your mod.rs. A full example follows:
My structure:
src/
├── main.rs
├── protocol
│ └── thing.rs
└── protocol.rs
main.rs
mod protocol;
fn main() {
let a = protocol::Thing::new();
println!("Hello, {:?}", a);
}
protocol.rs
pub use self::thing::Thing;
mod thing;
protocol/thing.rs
#[derive(Debug)]
pub struct Thing(i8);
impl Thing {
pub fn new() -> Thing { Thing(4) }
}
As a housekeeping bit, don't call files the same thing as language keywords. struct causes compilation problems, so I renamed it. Also, your struct creation syntax was incorrect, so I picked the shorter version for this example ^_^.
And to answer the question posed in your title: Without using esoteric features, a file always creates a new module — you can't put something into a different file without also putting it in a different module. You can re-export the type so it doesn't look like it though.
Further explanation: The mod keyword tells the compiler to look for a file by that name and reference it from the current file as a module. For example, mod protocol; will look for a file protocol.rs and behave as if it had included its contents, similar to:
mod protocol {
// ... contents here
};
See Rust by Example for more details.
With mod.rs:
src/
├── main.rs
└── protocol
├── mod.rs
└── thing.rs
protocol/thing.rs
pub struct Struct {
members: i8
}
impl Struct {
pub fn new() -> Struct {
Struct { members: 4 }
}
}
protocol/mod.rs
pub mod thing;
main.rs
mod protocol;
fn main() {
protocol::thing::Struct::new();
}