Skip to content

Instantly share code, notes, and snippets.

@lukebergen
Last active July 3, 2023 16:47
Show Gist options
  • Save lukebergen/bdd026c4676c34d155b3a8e1911092e0 to your computer and use it in GitHub Desktop.
Save lukebergen/bdd026c4676c34d155b3a8e1911092e0 to your computer and use it in GitHub Desktop.

From Mastadon post.

Working my way through the #rust book. Little confused by something in the modules section. Can't quite fit the whole thing in one toot, so here's a gist: <here>

Short version, useing nested modules. Does this allow access to ancestor modules or not?


In the modules section, the author refers back to the "guessing game" section and shows this:

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
}

From this, I figure "oh ok. We've included Rng from the rand module. Then we use the thread_rng function which is in the rand module. I guess because we've useed rand::Rng we now have access to public things in the rand module?

But then, testing this out, I do this:

// src/main.rs
use module_test::foo::bar;

fn main() {
    println!("{}", foo::get_3());
    println!("{}", bar::get_5());
}
// src/lib.rs
pub mod foo {
    pub fn get_3() -> u32 { 3 }

    pub mod bar {
        pub fn get_5() -> u32 { 5 }
    }
}

This fails to compile with error: use of undeclared crate or module foo

So what gives? If I use foo::bar::baz, does that allow me to do things off of foo itself or not?

Seems like not. But if not, then how does the use rand::Rng allow us to then access rand::other_non_Rng_things?

@keldin-coding
Copy link

So you can always use a fully qualified list. In this case rand::thread_rng is a function, no use is even necessary to get it.

However, the use statement is for pulling in the Rng implementation of things that adds methods like gen and gen_range to the ThreadRng returned by thread_rng. It's a bit of a trick. use rand::Ring isn't giving you access to anything so much as it's pulling in the definition of methods on the ThreadRng struct so that they exist (e.g, gen_range). You always have access to public function on modules as long as you fully qualify them

In your examples, you would be able to do:

println!("{}", module_test::foo::get_3());

or

use module_test::foo;

println!("{}", foo::get_3());

For a bigger example:

pub mod foo {
    pub mod baz {
        pub fn vroom() -> u64 { 3 }
    }
}

use foo::baz;
use foo::baz::vroom;

fn main() {
    // println!("{}", rand::thread_rng().gen());
    println!("{}", foo::baz::vroom());
    println!("{}", baz::vroom()); // enabled by use foo::baz;
    println!("{}", vroom());      // enabled by use foo::baz::vroom
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c5d2b44c45eddd78c98379b8ef033420

@lukebergen
Copy link
Author

lukebergen commented Jul 1, 2023

@lirossarvet Ooohh. That makes all of the sense. Thanks for clearing that up for me

@keldin-coding
Copy link

fn main() {
    println!("{:?}", rand::thread_rng());
}

as an addition to that, this works perfectly fine with no use statements because we aren't relying on any of the implementations of the Rng trait. in short, if you want anything from a trait, you have to explicitly opt-in by use'ing the trait.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment