OK, update. First of all, the new link is here, because the old one took too long to execute. Second of all, the second approach now IS faster, by quite a lot. For sequential access, however, the second was slower. For random access and modify, the second is faster. Any ideas?
Even on your initial attempt, I got these results:
Mem::replace based approach took 2657210
Clone based approach took 2983794
I'm pretty sure that 2983794 > 2657210.. Also, this makes sense, the clone approach has to copy the buffer each time.
On a second attempt I got:
Mem::replace based approach took 3652959
Clone based approach took 3020418
Hmm, mixed results. Time for a bit of number crunching! Here is the test I ran. I ran it on my pc, as it would've taken ages on the playground, and even then took alot of my cpu:
I think it's tough to extrapolate from any result you're getting here, since a sufficiently-smart compiler could notice that you're just overwriting the_vec[1] every time (and not ever using the value), and remove most of the code. (The only stuff that really needs to stay is the random number generation.)
Consider making an example that actually uses the output, if you want meaningful measurements.
Wow, just saw the code, and there are so many other stuff you are doing on top of your write operation: you are not doing x.clone() but X::new().clone();
(the cloning may be optimized away, although unlikely),
but more importantly: X::new() does push into an empty vec 500000 times. This means countless reallocations. I am pretty sure this is what is bottlenecking the whole operation, which leads to random timings due to the abusive heap usage.
You should definitely clean that before benchmarking!
This means creating the Vec using Vec::with_capacity(500000) instead of Vec::new(). Now, this is not DRY, since you get two times a magic numbers. You thus then need to set it within a constant.
More generally, though, collecting should be preferred to mutation (pushing) when building a Vec (or any kind of collection) since it will do the right preallocations for you:
For instance, instead of doing
let mut v: Vec<usize> = Vec::new();
for _ in 0 .. 500000 {
v.push(rng.gen());
}
you can do
let v: Vec<usize> =
(0 .. 500000)
.map(|_| rng.gen())
.collect();