My goal is to create some generic struct, let's call it Sampler, that will implement the Distribution<Outcome> trait from the rand crate for some type Outcome.
where Blocks is some iterator that yield iterators that each sample block_size times. That is, something like
struct Blocks<'a, R> {
sampler: &'a Sampler,
block_size: usize,
rng: R,
}
impl<'a, R: Rng> Iterator for Blocks<R> {
type Item = Outcome;
fn next(&mut self) -> Option<Self::Item> {
Some(
an iterator that call block_size times the
sample method of sampler with the given rng
)
}
}
Finally, I want to use Sampler in a Monte Carlo simulation over many threads. And I want reproducibility of the simulation by specifying some seed for the rng. I plan to use the xoshiro rng to do that.
Well first, if you want to store a reference to the Sampler in your Blocks iterator, you should take self by reference, not by value in your blocks method.
As for your returned iterator.. what exactly do you want it to do? You want an iterator of iterators that does what?
The main challenge you will run into is that the functions on the Rng trait require &mut self to be called, which in turn means that you need exclusive access to call them. Furthermore the iterator trait is such that the returned items do not borrow from the iterator, and therefore you can create several independent iterators that coexist:
let mut blocks = sampler.blocks();
let iter1 = blocks.next().unwrap();
let iter2 = blocks.next().unwrap();
// now use both iter1 and iter2
As you can see, neither iter1 nor iter2 would have exclusive access to the Rng in this case. To avoid this you can either:
Use a RefCell.
Create a new Rng per returned iterator, so each of them has exclusive access to its own rng.
Generate all 10 samples in the call to next and return a std::vec::IntoIter.
Note that if your sampler only requires &self to generate a sample, e.g. if you have this signature: