38

What is the closest equivalent Rust code to this Python code?

a, b = 1, 2
a, b = b, a + b

I am trying to write an iterative Fibonacci function. I have Python code I want to convert to Rust. Everything is fine, except for the swap part.

def fibonacci(n):
    if n < 2:
        return n
    fibPrev = 1
    fib = 1
    for num in range(2, n):
        fibPrev, fib = fib, fib + fibPrev
    return fib
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Nsukami _
  • 777
  • 1
  • 11
  • 15
  • Please make sure to read [*The Rust Programming Language*](http://doc.rust-lang.org/stable/book/). It covers lots of introductory topics. – Shepmaster Aug 04 '15 at 00:22
  • 2
    @Shepmaster, spent some time reading about [swap](http://doc.rust-lang.org/std/mem/fn.swap.html) and [replace](http://doc.rust-lang.org/std/mem/fn.replace.html) but not sure if what I need here. – Nsukami _ Aug 04 '15 at 05:40
  • https://doc.rust-lang.org/std/mem/fn.swap.html – Eric Jul 13 '21 at 13:46

2 Answers2

51

When swapping variables, the most likely thing you want is to create new bindings for a and b.

fn main() {
    let (a, b) = (1, 2);
    let (b, a) = (a, a + b);
}

For your actual case, you want to modify the existing bindings. Rust 1.59 will stabilize destructuring assignment:

fn fibonacci(n: u64) -> u64 {
    if n < 2 {
        return n;
    }
    let mut fib_prev = 1;
    let mut fib = 1;
    for _ in 2..n {
        (fib_prev, fib) = (fib, fib + fib_prev);
    }
    fib
}

Before Rust 1.59, you can use a temporary variable:

fn fibonacci(n: u64) -> u64 {
    if n < 2 {
        return n;
    }
    let mut fib_prev = 1;
    let mut fib = 1;
    for _ in 2..n {
        let next = fib + fib_prev;
        fib_prev = fib;
        fib = next;
    }
    fib
}

You could also make it so that you mutate the tuple:

fn fibonacci(n: u64) -> u64 {
    if n < 2 {
        return n;
    }
    let mut fib = (1, 1);
    for _ in 2..n {
        fib = (fib.1, fib.0 + fib.1);
    }
    fib.1
}

You may also be interested in swapping the contents of two pieces of memory. 99+% of the time, you want to re-bind the variables, but a very small amount of time you want to change things "in place":

fn main() {
    let (mut a, mut b) = (1, 2);
    std::mem::swap(&mut a, &mut b);

    println!("{:?}", (a, b));
}

Note that it's not concise to do this swap and add the values together in one step.

For a very concise implementation of the Fibonacci sequence that returns an iterator:

fn fib() -> impl Iterator<Item = u128> {
    let mut state = [1, 1];
    std::iter::from_fn(move || {
        state.swap(0, 1);
        let next = state.iter().sum();
        Some(std::mem::replace(&mut state[1], next))
    })
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    can you elaborate on when someone would want to change things in place vs re-binding the variables? Also, what's wrong with creating new bindings? Not efficient? – No_name Jul 03 '17 at 16:52
  • 1
    @No_name You can't re-bind in a loop (well, you can, but the new values will be lost on the next iteration). So for example it can't be (directly) used for calculating the factorial. – Antony Hatchkins Aug 23 '19 at 04:57
7

In addition, a better way to implement the Fibonacci sequence in Rust is using the Iterator trait:

// Iterator data structure
struct FibIter(u32, u32);

// Iterator initialization function
fn fib() -> FibIter {
    FibIter(0u32, 1u32)
}

// Iterator trait implementation
impl Iterator for FibIter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        *self = FibIter(self.1, self.1 + self.0);
        Some(self.0)
    }
}

fn main() {
    println!("{:?}", fib().take(15).collect::<Vec<_>>());
}

See The Rust Programming Language chapter on iterators.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
aSpex
  • 4,790
  • 14
  • 25