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
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);
}
However, in your actual case, there isn't a nice solution. When you do as above, you always create new bindings for a
and b
, but you want to modify the existing bindings. One solution I know of is to use a temporary:
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.
See also:
- Can I destructure a tuple without binding the result to a new variable in a let/match/for statement?
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.
I'm surprised none of the answers mention the XOR-swap:
fibPrev ^= fib;
fib ^= fibPrev;
fibPrev ^= fib;
This is a well-known way to swap two values without using a temporary variable or risking integer overflow.
Note that with modern optimizing compilers, in most cases it's better from performance standpoint to just use a temporary variable (see link in the comment by trentcl). There are, however, some use cases for the XOR-swap, the linked Wikipedia article provides a decent overview of its pros and cons.
Interestingly enough, if you were to implement a XOR-swap as a function in rust, you don't need to check if you're trying to swap a variable with itself (in which case you'll end up with it being set to zero due to the properties of a XOR operation). Compare swap implementations in rust:
fn swap(a: &mut i32, b: &mut i32) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
and C++:
void swap(int& a, int& b) {
if (&a == &b) return; // Avoid swapping the variable with itself
a ^= b;
b ^= a;
a ^= b;
}
If you try to call swap like this in rust:
let mut a = 42;
swap(&mut a, &mut a);
You will get a compilation error:
error[E0499]: cannot borrow `a` as mutable more than once at a time
--> src/main.rs:27:18
|
27 | swap(&mut a, &mut a);
| ---- ------ ^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call