When/Why do Rust Traits Need to be `use`d/Imported

Viewed 259

When/why do Rust traits need to be used/Imported, or why does this question not make sense?

I'm an experienced programmer, but I'm new to Rust.

I'm working my way through The Rust Programming Language -- in chapter 2 there's the following statment.

First, we add a use line: use rand::Rng. The Rng trait defines methods that random number generators implement, and this trait must be in scope for us to use those methods. Chapter 10 will cover traits in detail.

Emphasis mine.

It's not clear to me why this program

use std::io;
use rand::Rng;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    println!("The secret number is: {}", secret_number);

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}

needs to use rand::Rng. When we use/imported the std::io symbol, we got access to an io symbol that we could call associated functions on.

io::stdin

In my naive (and incorrect) view, using use rand::Rng would give us an Rng symbol. Instead, we got a rand symbol that we could call a thread_rng method on.

let secret_number = rand::thread_rng().gen_range(1, 101);

My naive view would be that in order to call thread_rng, we'd need to do something like

use rand;
// or
use rand::rand

What am I, as the programmer, doing when I put use rand::Rng in my program, and why is this different from use std::io?

1 Answers

The rand "symbol" is the name of an external crate, which is in the root namespace irrespective of any use statements. It defines a function thread_rng() that is also available (through namespace-qualification with rand::) irrespective of your use statements.

Therefore, even without your use statements, you can do:

let thread_rng = rand::thread_rng();

However, thread_rng returns a rand::rngs::ThreadRng struct, upon which you are attempting to call gen_range—and it is this function that is a trait method, which is not in-scope until the rand::Rng trait is brought in with a use statement.

It is actually possible to call trait methods even without use statements:

rand::Rng::gen_range(&mut rand::thread_rng(), 1, 101);

...but generally speaking, use is much cleaner.

Related