Tumbleweed53
Tumbleweed53

Reputation: 1551

Mutable vs. immutable borrows in closure?

I can't figure out how to get the following to work. I think I need the closure to borrow by &mut Vec, but I don't know how to express that. This is distilled from a larger function, but shows the same error.

fn main() {
    let mut v = vec![0; 10];

    let next = |i| (i + 1) % v.len();

    v[next(1usize)] = 1;

    v.push(13);

    v[next(2usize)] = 1;    
}

Error:

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
 --> a.rs:9:5
  |
5 |     let next = |i| {
  |                --- immutable borrow occurs here
6 |         (i + 1) % v.len()
  |                   - first borrow occurs due to use of `v` in closure
...
9 |     v[next(1usize)] = 1;
  |     ^ ---- immutable borrow later used here
  |     |
  |     mutable borrow occurs here

error: aborting due to previous error

Upvotes: 9

Views: 3569

Answers (4)

Aplet123
Aplet123

Reputation: 35482

In addition to the other answers here, you can use a macro to scope v so you don't have to pass it in every call:

fn main() {
    let mut v = vec![0; 10];

    macro_rules! next {
        // rule to get an index
        ($i: expr) => {
            ($i + 1) % v.len()
        };
        // rule to mutate the vector
        ($i: expr => $v: expr) => {{
            let ind = next!($i);
            v[ind] = $v;
        }};
    };
    // get an index
    let ind = next!(1usize);
    // mutate the vector
    v[ind] = 1;
    v.push(13);
    // or, with the mutation syntax
    next!(2usize => 3);
    println!("{:?}", v);
}

Upvotes: 1

Acorn
Acorn

Reputation: 26066

If you really want to do it with a closure, you will have to pass the vector by parameter:

let next = |v: &Vec<_>, i| (i + 1) % v.len();

This makes the closure borrow per-call, rather than capture for the scope. You still need to separate the borrows, though:

let j = next(&v, 1usize);
v[j] = 1;

To make your life easier, you can put everything inside the closure instead:

let next = |v: &mut Vec<_>, i, x| {
    let j = (i + 1) % v.len();
    v[j] = x;
};

Which allows you to simply do:

next(&mut v, 1usize, 1);
next(&mut v, 2usize, 2);
// etc.

This pattern is useful for cases where you are writing a closure just for avoiding local code repetition (which I suspect is why you are asking given the comments).

Upvotes: 7

Eric Seppanen
Eric Seppanen

Reputation: 6081

A closure probably isn't the right tool for the job. The compiler is unhappy because your closure has taken a reference against your Vec, but then while that closure reference is still outstanding you're trying to mutate the Vec. Under Rust's borrow rules, that's not allowed.

The most straightforward approach would be storing your data inside a struct, and making next a member function. That way, there's no closure taking references; it can just check the length only when needed.

struct WrapVec<T>(Vec<T>);

impl<T> WrapVec<T> {
    fn wrap_next(&mut self, index: usize) -> &mut T {
        let index = (index + 1) % self.0.len();
        &mut self.0[index]
    }
}

fn main() {
    let mut v = WrapVec(vec![0; 10]);
    *v.wrap_next(1) = 1;
    v.0.push(13);
    *v.wrap_next(2) = 1;
}

If you want to be able to apply this function to any Vec, then you may find it useful to define a new trait. For example:

trait WrapNext<T> {
    fn wrap_next(&mut self, index: usize) -> &mut T;
}

impl<T> WrapNext<T> for Vec<T> {
    fn wrap_next(&mut self, index: usize) -> &mut T {
        let index = (index + 1) % self.len();
        &mut self[index]
    }
}

fn main() {
    let mut v = vec![0; 10];
    *v.wrap_next(1) = 1;
    v.push(13);
    *v.wrap_next(2) = 1;
}

Upvotes: 1

vallentin
vallentin

Reputation: 26157

Since the closure only needs the length of the Vec. Then instead, you can just get that prior to the closure. Then you avoid the whole borrowing issue, as the closure doesn't need to borrow v anymore.

fn main() {
    let mut v = vec![0; 10];

    let len = v.len();
    let next = |i| (i + 1) % len;

    v[next(1usize)] = 1;
}

Assuming your closure is not dependent on other things, then instead of a closure, you could define a trait with a method that does that.

For simplicity let's call the trait VecExt and the method set.

trait VecExt<T> {
    fn set(&mut self, index: usize, value: T);
}

impl<T> VecExt<T> for Vec<T> {
    fn set(&mut self, index: usize, value: T) {
        let len = self.len();
        self[(index + 1) % len] = value;
    }
}

fn main() {
    let mut v = vec![0; 10];

    v.set(1, 1);

    v.push(13);

    v.set(2, 1);
}

Upvotes: 2

Related Questions