Returning a RNG iterator from a function

I want a function that will return an iterator for random numbers, possibly with things like maps and filters applied.

I realize that the problem with my approach below is that I'm trying to capture a reference to thread_rng and Uniform without making them dynamic.

What is the idomatic way to solve this problem? Should my function use Box and put things on the heap, or should I make a struct generator that has fields for each of the objects, and give that a next method? Something else?

use rand::{thread_rng};
use rand::distributions::{Distribution,Uniform};

fn my_gen<'a>() -> impl Iterator<Item=f32> + 'a {
    let mut rng = thread_rng();
    let uniform = Uniform ::new(1.0, 1.3);
    uniform.sample_iter(&mut rng)
}

fn main() {
    let m = my_gen();
    println!("{}", m.unwrap().to_string());
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing local variable `rng`
 --> src/main.rs:7:5
  |
7 |     uniform.sample_iter(&mut rng)
  |     ^^^^^^^^^^^^^^^^^^^^--------^
  |     |                   |
  |     |                   `rng` is borrowed here
  |     returns a value referencing data owned by the current function
  |
  = help: use `.collect()` to allocate the iterator

error[E0599]: no method named `unwrap` found for opaque type `impl Iterator<Item = f32>` in the current scope
  --> src/main.rs:12:22
   |
12 |     println!("{}", m.unwrap().to_string());
   |                      ^^^^^^ method not found in `impl Iterator<Item = f32>`

Some errors have detailed explanations: E0515, E0599.
For more information about an error, try `rustc --explain E0515`.
error: could not compile `playground` due to 2 previous errors

You can just skip the reference and do

fn my_gen<'a>() -> impl Iterator<Item = f32> + 'a {
    let uniform = Uniform::new(1.0, 1.3);
    uniform.sample_iter(thread_rng())
}
1 Like

That works in the playground, but when I build this with rustc 1.61.0, I get E0308:

         .sample_iter(thread_rng())
                      ^^^^^^^^^^^^
                      |
                      expected `&mut _`, found struct `ThreadRng`
                      help: consider mutably borrowing here: `&mut thread_rng()`
   = note: expected mutable reference `&mut _`
                         found struct `ThreadRng`

Update your rand version in cargo.toml to the latest, 0.8.5 and it should work.

1 Like

If you need to keep using the old version of rand, you can make your own iterator:

std::iter::repeat_with(move || uniform.sample(&mut rng))
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.