The rust by example guide shows the following code here for a fibonacci series with iterators:
fn next(&mut self) -> Option<u32> {
let new_next = self.curr + self.next;
let new_curr = mem::replace(&mut self.next, new_next);
// 'Some' is always returned, this is an infinite value generator
Some(mem::replace(&mut self.curr, new_curr))
}
I would like to understand what is the advantage of this, over the most intuitive (if you come from other languages):
fn next(&mut self) -> Option<u32> {
let tmp = self.next;
self.next = self.curr + self.next;
self.curr = tmp;
Some(self.curr)
}
It's not always possible to write the direct code, due to Rust's ownership. If self.next
is storing a non-Copy
type (e.g. Vec<T>
for any type T
) then let tmp = self.next;
is taking that value out of self
by-value, that is, moving ownership, so the source should not be usable. But the source is behind a reference and references must always point to valid data, so the compiler cannot allow moving out of &mut
: you get errors like cannot move out of dereference of `&mut`-pointer
.
replace
gets around these issues via unsafe
code, by internally making the guarantee that any invalidation is entirely made valid by the time replace
returns.
You can see this answer for more info about moves in general, and this question for a related issue about a swap
function (replace
is implemented using the standard library's swap
internally).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With