-1

While trying to compile the following code, im getting an error:

error[E0502]: cannot borrow var as immutable because it is also borrowed as mutable

fn increment(num : &mut i32){
    *num = *num +1;
}

fn main() {
    let mut var : i32 = 123;
    let p_var: &mut i32   = &mut var;

    println!("{}", var);
    increment(p_var);
}

I have no clue what does it mean, can someone explain me exacly why am I getting this error?

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
BIGoperaFAN
  • 103
  • 7
  • 1
    Does it go away if you move the `println` before `let p_var ...` line? – Fildor Jul 22 '22 at 22:16
  • 3
    This kind of error is explained in the [Rust book](https://doc.rust-lang.org/book/). You probably want to start there, because aliasing rules are covered pretty early on. Basically, you're trying to use Rust before you have learned it. – cdhowie Jul 22 '22 at 22:22
  • @Fildor Yes it does but what I wanted to achieve here was to invoke println!() and increment() alternately so that I can see variable changing its value – BIGoperaFAN Jul 22 '22 at 22:24
  • @cdhowie cool but where is it exacly in the Rust book? – BIGoperaFAN Jul 22 '22 at 22:25
  • https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html and following – Fildor Jul 22 '22 at 22:30

2 Answers2

2
fn increment(num: &mut i32){
    *num = *num +1;
}

fn main() {
    let mut var : i32 = 123;
    
    println!("{}", var);
    increment(&mut var);
    println!("{}", var);
}

worked for me.

I, myself, am a Rust beginner, too. So, here is what my view on this is ( I MAY be utterly wrong ):

In this code var never gives up ownership and has no mutable borrows that are still in scope when it borrows immutably. I therefore can borrow it mutably to the increment function. After it has returned that borrow is not alive anymore. I therefore can borrow var` again to the println macro.

When you assigned to p_var you created a mutable borrow that was in scope and alive when you tried to borrow to the println macro, which is not allowed.

This is what the incredible cargo told me:

error[E0502]: cannot borrow `var` as immutable because it is also borrowed as mutable
  --> src/main.rs:9:20
   |
7  |     let p_var : &mut i32 = &mut var;
   |                            -------- mutable borrow occurs here
8  |
9  |     println!("{}", var);
   |                    ^^^ immutable borrow occurs here
10 |     increment(p_var);
   |               ----- mutable borrow later used here
   |

It would be great if some more experienced rustacian could verify (or correct) my reasoning and assessment.

Fildor
  • 14,510
  • 4
  • 35
  • 67
  • It does work, thank you, but I still dont understand why cant I use seperate reference and invoke funcitons like you – BIGoperaFAN Jul 22 '22 at 22:33
  • 3
    @BIGoperaFAN one of the ownership/borrowing rules is *"mutable references are exclusive"* which means no one else can modify or even read the value while there's a mutable reference still alive. – kmdreko Jul 22 '22 at 23:03
  • @Fildor *"still alive"* does NOT mean *"still in scope"* thanks to [non-lexical-lifetimes](https://stackoverflow.com/questions/50251487/what-are-non-lexical-lifetimes). The borrow checker will consider the reference "alive" only until its last usage. – kmdreko Jul 22 '22 at 23:09
  • @kmdreko Thx for the clarification. Still learning. So my explanation in the answer is wrong? Or at least not accurate? – Fildor Jul 22 '22 at 23:13
  • ^^ I edited to take kmdreko's information into account. – Fildor Jul 22 '22 at 23:28
0

It's not possible due to Rust mutable reference rules.

Until there is a mutable reference is alive in a lifetime scope, the only way to access that referent is the that alive reference.

In your case you already have p_var alive, so the only way to access it is through p_var. Hence you are violating the rust mutable reference rules.

For example this works:

fn increment(num : &mut i32){
    *num = *num +1;
}

fn main() {
    let mut var : i32 = 123;
    
    
    {
        let p_var: &mut i32   = &mut var;
        increment(p_var);
    }
        

    println!("{}", var);
}

This works because println!("{}", var) ran, p_var life time has already ended. If you try to reference var inside the {} scope it won't work either.

foragerDev
  • 1,307
  • 1
  • 9
  • 22
  • I dont quite understand how invoking ``println!`` with ``var`` is counted as borrowing – BIGoperaFAN Jul 23 '22 at 19:22
  • 2
    @BIGoperaFAN `println!` needs to be able to read `var` to print it. It could take ownership of `var` (ie. you could move `var` into `println!`), but then you wouldn't be able to use it after printing it. This is probably never what you want, so `println!` always borrows its arguments. – tobiasvl Jul 23 '22 at 20:59
  • @tobiasvl Thanks, your comment explaines everything. I was thinking it could not borrow because Im passing ``var`` and not ``&var`` to it, but now im reading this: https://stackoverflow.com/questions/30450399/does-println-borrow-or-own-the-variable. – BIGoperaFAN Jul 24 '22 at 17:06