The Acorn
The Acorn

Reputation: 33

Why does rust consider borrows active in other branches

It appears the borrow checker considers other branches to hold borrows. For example

fn f(v: &mut Vec<i32>, a: bool) -> &i32 {
    match &v[0] {
        _ if a => {
            f(v, !a);
            &v[0]
        }
        x => {
            x
        }
    }
}

will not compile.

See it in the Rust Playground.

The error is:

error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable
 --> src/lib.rs:4:13
  |
1 | fn f(v: &mut Vec<i32>, a: bool) -> &i32 {
  |         - let's call the lifetime of this reference `'1`
2 |     match &v[0] {
  |            - immutable borrow occurs here
3 |         _ if a => {
4 |             f(v, !a);
  |             ^^^^^^^^ mutable borrow occurs here
...
8 |             x
  |             - returning this value requires that `*v` is borrowed for `'1`

Why does it do this and how do I get around it?

Upvotes: 3

Views: 393

Answers (1)

Hadus
Hadus

Reputation: 1664

I think this is a limitation of the current borrow checker and the new one Polonius will accept this.

Getting around this is usually done by re-arranging some control flow logic or by not using a reference in the match (cloning it or dereferencing copy types).

In the example, this is how you get around it:

fn f(v: &mut Vec<i32>, a: bool) -> &i32 {
    if a {
        f(v, !a);
    }
    &v[0]
}

or by using the fact that i32 is Copy:

fn f(v: &mut Vec<i32>, a: bool) -> &i32 {
    match v[0] {
        _ if a => {
            f(v, !a);
            &v[0]
        }
        _ => &v[0],
    }
}

For the example, the second method doesn't make too much sense but maybe for your use case doing this is easier/nicer.

Upvotes: 4

Related Questions