This code from the docs shows how to generate a random number.
let mut rng: ThreadRng = rand::thread_rng();
let y: f64 = rng.gen();
The gen() method is missing and requires importing.
In my IDE I just press a key to import missing symbols, and this appears at the top of the file.
use rand::Rng;
But I am confused about how this trait was chosen. The ThreadRng struct looks like this, and there's an another block implementing the RngCore trait.
pub struct ThreadRng {
// Rc is explicitly !Send and !Sync
rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
}
impl RngCore for ThreadRng {
...
}
But Rng is nowhere to be seen (I know where it is, but I wouldn't have found it without IDE autoimports).
If this were a Java program, for example, ThreadRng or something inheriting it would contain the method gen() if it implemented the Rng interface.
My question is how to navigate Rust code to find the right things to import? Is there something analogous to looking for implementations of an interface in Java?
Yes, it's the "Implementors" section of a trait, though it does not show every type implementing that trait (types from 3rd party crates that implement that trait are not part of that list). With Rng it is a little bit more complicated, as it has a supertrait (RngCore) and is implemented for every type that implements RngCore. These kind of traits are called extension traits (I think), exposing extra functionality based on a supertrait, without any need for implementing it. This is similar to Stream and StreamExt, for example. You implement the former and get the latter for free.
So usually you'll get the right imports from its documentation.
But rand crate only shows a basic example by importing a prelude mod (use rand::prelude::*;).
And also unfortunately rustdoc doesn't show the indirect blanket impl on ThreadRng and there is no indicator on RngCore rustdoc page except an unconspicuous sentence
End users should normally use the Rng trait from the rand crate, which is automatically implemented for every type implementing RngCore.
So you still rely on a friendly documentation to know which trait you should use.
error[E0412]: cannot find type `ThreadRng` in this scope
--> src/main.rs:2:18
|
2 | let mut rng: ThreadRng = rand::thread_rng();
| ^^^^^^^^^ not found in this scope
|
help: consider importing this struct
|
1 + use rand::rngs::ThreadRng;
|
I add the import
use rand::rngs::ThreadRng;
fn main() {
let mut rng: ThreadRng = rand::thread_rng();
let y: f64 = rng.gen();
}
error[E0599]: no method named `gen` found for struct `ThreadRng` in the current scope
--> src/main.rs:4:22
|
4 | let y: f64 = rng.gen();
| ^^^ method not found in `ThreadRng`
|
::: /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rand-0.8.5/src/rng.rs:93:8
|
93 | fn gen<T>(&mut self) -> T
| --- the method is available for `ThreadRng` here
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
1 + use rand::Rng;
|
I add the other import (by the way in the playground, you can even click on those suggestions to apply them) and it works:
use rand::Rng;
use rand::rngs::ThreadRng;
fn main() {
let mut rng: ThreadRng = rand::thread_rng();
let y: f64 = rng.gen();
}
Huh, might be a good idea to rebuild the docs for the latest version of all crates that were built with an old version? Once a year or so. Can't do it too often, and need to spread out the load over time obviously.
I occasionally come across crates that have way different formatting (no dark theme for a start). I assume they are also affected by this? (But maybe that is good as a warning to the reader that something is outdated?)