Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mem::replace in Rust

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)
}
like image 981
Hernan Avatar asked Nov 29 '14 01:11

Hernan


1 Answers

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).

like image 151
huon Avatar answered Nov 19 '22 20:11

huon