15

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)
}
Steven
  • 5,654
  • 1
  • 16
  • 19
Hernan
  • 5,811
  • 10
  • 51
  • 86

1 Answers1

18

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

Community
  • 1
  • 1
huon
  • 94,605
  • 21
  • 231
  • 225
  • 1
    Thanks for the answer. It was very clear. I have to say that even though I have followed most of the Rust guides, I am still not clear about certain things. In other words, I can read/change a program but I am not sure I would make the right decisions if I have to make it from scratch. Can you suggest some other guide for this. – Hernan Nov 29 '14 at 19:19
  • @Hernan, there's [Rust by Example](http://rustbyexample.com/) but I'm not sure if that's what you're looking for. For "making the right decisions" the compiler errors theoretically guide you in the right direction, there's some general guidelines like "cannot move out of ..." suggests using a reference or using a function like `replace` or `swap`, "cannot borrow ..." suggests using more `{}` scopes. (With practice you can predict when the compiler complains and use do the fix immediately, but my internal dialog is still essentially "the compiler will complain about this".) – huon Nov 30 '14 at 06:55
  • I should have said "the right decisions" in the design. I will keep reading and coding. – Hernan Dec 01 '14 at 02:01
  • Example can be see on this page: http://cglab.ca/%7Eabeinges/blah/too-many-lists/book/first-push.html – o0omycomputero0o Feb 24 '18 at 07:03