Gong-Yi Liao
Gong-Yi Liao

Reputation: 609

BigUint and "cannot move out of borrowed content" error

I tried to follow the iterator approach described in Rust by Example's Iterator section with BigUint:

extern crate num_bigint;

use num_bigint::{BigUint, ToBigUint};

struct FibState {
    a: BigUint,
    b: BigUint,
}

impl Iterator for FibState {
    type Item = BigUint;
    fn next(&mut self) -> Option<BigUint> {
        let b_n = self.a + self.b;
        self.a = self.b;
        self.b = b_n;
        Some(self.a)
    }
}

fn fibs_0() -> FibState {
    FibState {
        a: 0.to_biguint().unwrap(),
        b: 1.to_biguint().unwrap(),
    }
}

fn fib2(n: usize) -> BigUint {
    if n < 2 {
        n.to_biguint().unwrap()
    } else {
        fibs_0().skip(n - 1).next().unwrap()
    }
}

fn main() {
    println!("Fib1(300) = {}", fib2(300));
}

The above code does not compile:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:13:19
   |
13 |         let b_n = self.a + self.b;
   |                   ^^^^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:13:28
   |
13 |         let b_n = self.a + self.b;
   |                            ^^^^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:14:18
   |
14 |         self.a = self.b;
   |                  ^^^^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:16:14
   |
16 |         Some(self.a)
   |              ^^^^ cannot move out of borrowed content

I am not sure if it is due to the BigUint type is not primitive thus it does not have the Copy trait. How can I modify the iterator to make it works with the FibState struct?

Upvotes: 0

Views: 151

Answers (1)

Shepmaster
Shepmaster

Reputation: 431669

fn next(&mut self) -> Option<BigUint> {
    let b_next = &self.a + &self.b; 
    let b_prev = std::mem::replace(&mut self.b, b_next);
    self.a = b_prev;
    Some(self.a.clone())
}
  1. BigUint does not implement Copy, but the Add trait takes both arguments by value. BigUint implements Add for references as well, so you can take references of the values instead.

  2. We would like to replace the current value of b with the next value of b, but we need to keep the old value. We can use mem::replace for that.

  3. Assigning the old b value to a is straightforward.

  4. Now we wish to return the value in a, so we need to clone the entire value.

BigUint type is not primitive thus it does not have the Copy trait

Something being a primitive and something implementing the Copy trait have nothing to do with each other. User types can implement Copy and some primitives do not implement Copy.

See also:

Upvotes: 1

Related Questions