0

I'm trying to nail down ownership rules. I want to:

  • start with a mutable reference to a slice
  • make some edits to its contents
  • reduce the slice reference to a reference of a sub-slice and repeat

Below is my attempt:

pub fn example() {
    // Make a mutable slice
    let mut v = [0, 1, 2, 3];

    // Make a mutable reference to said slice
    let mut v_ref = &mut v[..];

    while v_ref.len() > 1 {
        // Involves some edits -> need mut
        v_ref.swap(0, v_ref.len() - 1);

        // Try to reduce slice to sub-slice (some simplification here)
        // Errors!
        let (v_l, v_h) = v.split_at_mut(v.len() / 2);
        v_ref = v_l;
    }
}

However I'm getting the errors:

error[E0502]: cannot borrow `*v_ref` as immutable because it is also borrowed as mutable
  --> src/lib.rs:11:23
   |
11 |         v_ref.swap(0, v_ref.len() - 1);
   |         -----         ^^^^^          - mutable borrow ends here
   |         |             |
   |         |             immutable borrow occurs here
   |         mutable borrow occurs here

error[E0499]: cannot borrow `v` as mutable more than once at a time
  --> src/lib.rs:15:26
   |
7  |     let mut v_ref = &mut v[..];
   |                          - first mutable borrow occurs here
...
15 |         let (v_l, v_h) = v.split_at_mut(v.len() / 2);
   |                          ^ second mutable borrow occurs here
...
18 | }
   | - first borrow ends here

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
  --> src/lib.rs:15:41
   |
7  |     let mut v_ref = &mut v[..];
   |                          - mutable borrow occurs here
...
15 |         let (v_l, v_h) = v.split_at_mut(v.len() / 2);
   |                                         ^ immutable borrow occurs here
...
18 | }
   | - mutable borrow ends here

I understand that you can't have multiple references to an object in the same scope as a single mutable reference.

There should be a safe way to reduce a slice's range, as you're only reducing the scope of a current mutable reference. What's the best way to do that?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
CrepeGoat
  • 2,315
  • 20
  • 24
  • 1
    Once you have mutably borrowed `v` (i.e. `let mut v_ref = &mut v[..];`), you can't access `v` any more, until that borrow is over. That's because then you'd have borrowed it twice, which isn't allowed when one of the borrows is mutable. However, `v_ref` now points to the same data and you _can_ borrow `v_ref`. – Peter Hall Aug 26 '18 at 13:38
  • 1
    _"Why does it keep complaining about my uses of v.len()?"_ — The `len` method will borrow `v`, which isn't allowed because `v_ref` has already borrowed `v` mutably. Instead just use `v_ref.len()`, which points to the same data. – Peter Hall Aug 26 '18 at 13:40
  • *I understand that you can't have multiple references to an object in the same scope as a single mutable reference* — why are you trying to use multiple references to the same object then (`v` / `v_ref`)? – Shepmaster Aug 26 '18 at 14:00
  • Please don't edit your question such that it invalidates existing answers. You are welcome to edit your question to your heart's content before you post it and before an answer is provided. – Shepmaster Aug 26 '18 at 20:06
  • It does not invalidate the question - the typo did not contribute to the core of my problem – CrepeGoat Aug 26 '18 at 20:06
  • I did not say it invalidated the *question*, but that it invalidates the *answer*. If you remove the typos / bugs in your code, then 1/3 of the answer no longer makes any sense. – Shepmaster Aug 26 '18 at 20:08
  • Sorry, I'm embarrassed that I let typos leak in. This is my first posted question here, so thanks for explaining the SO question procedure. – CrepeGoat Aug 27 '18 at 18:16

1 Answers1

1

Problem 1: Using the same variable mutably and immutably

As Peter Hall points out, the code attempts to reference the variable v while there's a concurrent mutable reference to it, even though you don't care about v_ref anymore. A MCVE:

pub fn example() {
    let mut v = 0;
    let mut v_ref = &mut v;
    println!("{}", v)
}

See also:

Problem 2: Using the same variable mutably and immutably

Then the code attempts to overlap mutable and mutable borrows in a single function call. A MCVE:

pub fn example() {
    let mut v = [0, 1, 2, 3];
    v.split_at_mut(v.len());
}

See also:

Problem 3: Using the same variable mutably and mutably

Then the code has overlapping mutable borrows of v in the loop.

See also:


All together:

pub fn example() {
    let mut v = [0, 1, 2, 3];
    let mut v_ref = &mut v[..];

    while v_ref.len() > 1 {
        let len = v_ref.len();
        v_ref.swap(0, len - 1);
        let (v_l, _) = { v_ref }.split_at_mut(len / 2);
        v_ref = v_l;
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • This definitely fixed the reduced problem I gave you... but it didn't fix my actual problem :( thanks anyway – CrepeGoat Aug 26 '18 at 23:35
  • @CrepeGoat well, now you can figure out the difference between that and this and ask a new question. Feel free to pop into the [Rust SO chatroom](https://chat.stackoverflow.com/rooms/62927/rust) if you want help reducing it. – Shepmaster Aug 26 '18 at 23:40