5

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);
}
joel
  • 6,359
  • 2
  • 30
  • 55
grjash
  • 176
  • 2
  • 8

2 Answers2

7

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

fmendez
  • 7,250
  • 5
  • 36
  • 35
4

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.

rodrigo
  • 94,151
  • 12
  • 143
  • 190