How to have multiple files with one module? - module

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");
}

Related

How do I place a Rust module in a separate file? [duplicate]

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.

Why does Rust allow public access to a private module?

I am a newbie in Rust and just started to read the programming book while doing rustling exercises. In the modules2.rs exercise, I am confused why the following code compiles:
mod delicious_snacks {
pub use self::fruits::PEAR as fruit;
pub use self::veggies::CUCUMBER as veggie;
mod fruits {
pub const PEAR: &'static str = "Pear";
pub const APPLE: &'static str = "Apple";
}
mod veggies {
pub const CUCUMBER: &'static str = "Cucumber";
pub const CARROT: &'static str = "Carrot";
}
}
fn main() {
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie
);
}
Specifically, I am wondering why it is OK for main to access private fruits and veggies modules just because their uses are marked pub? On the other hand, if we don't use pub use, then, without making fruits and veggies pub, one cannot access e.g., delicious_snacks::fruits::PEAR in main because fruits is not public. Similarly, if we don't use pub for const PEAR, even with pub use self::fruits::PEAR as fruit, we still cannot compile delicious_snacks::fruit. So what exactly is the rule here? Why is it OK to not mark pub for those modules?
The constants PEAR/APPLE/CUCUMBER/CARROT are marked as pub, which means they can be accessed from everywhere, even if they're in a private module.
This is a common technique, to implement something in a private module, and re-export only the things we want, e.g.
// actual implementation is here
mod foo_internal;
pub use foo_internal::{Foo, Bar};
This still maintains privacy/visibility, since Foo and Bar can't be re-exported if they're private.
You can also create a new module hierarchy for users of your library:
mod foo_internal;
pub mod foo {
pub use foo_internal::Foo;
}
pub mod bar {
pub use foo_internal::Bar;
}
This clearly separates the public interface from implementation details, so the implementation can be freely refactored without changing the public modules.

How can I export just the functions of a module as part of another module? [duplicate]

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");
}

How do I "export" things from a submodule?

I'd like to write a mod.rs file like:
pub use foo::*;
mod foo;
pub mod bar;
But I get the error unresolved import foo. What's the correct way to do this?
Here's an MCVE of your problem:
pub mod sub {
use foo::function;
pub mod foo {
pub fn function() {}
}
}
fn main() {}
As Adrian mentions, the solution is to use the keyword self in the use statement:
pub mod sub {
use self::foo::function;
pub mod foo {
pub fn function() {}
}
}
fn main() {}
So, what's going on? The Rust Programming Language describes the problem:
What about the self? Well, by default, use declarations are absolute paths, starting from your crate root. self makes that path relative to your current place in the hierarchy instead.
That is, use foo means to use foo from the root of the crate. use self::foo means to use foo relative to the current module.

Move struct into a separate file without splitting into a separate module?

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();
}