as per my understanding, &i and &j is called borrow. But the book says '&i' is a reference.
this code below:
let i = 5;
let j = 6;
let r1 = &mut i;
let r2 = &mut i;
In the above case, compiler throws -> " &mut i; --- first mutable borrow occurs here " and "&mut i; --> second mutable borrow occurs here". so I assume r1 is reference and '&mut i' is 'mutable' borrow.
let i = 5;
let j = 6;
let mut r1 = &i;
let mut r2 = &i;
now by this, I have two mutable reference. this goes completely against 'At any given time, you can have either one mutable reference ... '
I see the compiler does 'borrow checker' and not 'reference checker'. Why it's wrtten like that in the book?
isn't the left side is reference and right side is borrow?
They are the same. At most, you can take the verb borrow to denote the act of taking a reference, but this difference is immaterial and purely linguistic.
No you don't. &i results in a shared (immutable) reference.
The exclusiveness of mutability doesn't concern the mutability of the reference itself; the mutability of values and places in Rust is basically just a lint — it could be completely eliminated while keeping the exact same memory model.
The exclusiveness of mutability is about the pointed place of a &mut reference, ie., it only matters when the place/value to be mutated is behind indirection.
The let mut r1 = &i; means that the variable r1 (ie., the reference itself) is mutable, so you can re-assign it to point to another place. It does NOT allow you to mutate i.
(Draw diagrams of the pointers and pointed values for yourself, and you'll find this trivial.)
Saying the same thing with different words in case it helps:
let mut variable = ... versus let variable = ... -- a mut or non-mut binding -- is the lint-like distinction. The mut does not change the type of the variable or anything like that. Given a program that compiles, making every binding a mut binding changes nothing aside from some lint-like warnings. A non-mut binding prevents overwriting or taking a &mut to the variable. It doesn't prevent mutation via indirection,[1] interior mutability,[2] or moving to a new mut binding[3] (or even moving to a new temporary place).
Rust doesn't actually have any surface syntax for shallow immutability so far,[5] and also has no way to enforce deep immutability at all.[6] Despite the mut syntax and what most learning material says, the real distinction in Rust is exclusive-vs-shared, not mutable-vs-immutable.
As far as my personal vocabulary goes, references are those & and &mut things, where as "borrows" is a more general concept. For example, an Iter<'_, T> can be a borrow of some slice, but doesn't actually contain any references (that you can observe outside of std, and also in the current implementation).
And even when all the types involved are references, a &[T] can be a borrow of a Vec<T> for example, even though the former is not a reference to a Vec<T>. That is, in my way of thinking, lifetimes being tied together via constraints like
// Desugared signature of `<Vec<T> as Deref>::deref`
fn deref<'a>(self: &'a Vec<T>) -> &'a [T]
is interpreted as the &[T] being or holding a borrow/reborrow of the &Vec<T>.
So as far as I'm concerned: references are borrows; not all borrows are references.
r1 is a variable (of type &i32) that holds the reference -> the moment you have 'of type &i32', isn't a reference then? so r1 cannot be a 'variable' but a reference?
the & operator is used to create such a reference -> you have said this.
let i = 4;
let r1 = &i;
println!("value is: {}", r1);
let r1 = 4;
println!("value is: {}", r1);
in the above code, if we go by like 'r1' is a variable on two occasions. How does Rust knows, the first time it's reference and second time it directly holds the value?
A variable can be a reference (a variable's type can be a reference type and its value be a reference value) in the same way that a variable can be a String (a variable's type can be String and its value be a String value).
References have some special language-level abilities, like reborrowing, but otherwise they are still types.[1] Rust references are roughly speaking pointers with stricter invariants and borrow checking. They're not magical aliases (in contrast with some other programming languages).
That's shadowing. They're two different variables. Rust knows they're different the same way it knows that these two variables are an i32 and a String. It's nothing reference specific.
I’m just on mobile so need to be brief but here we have to consider both types and values - you can have a variable that is of a reference type, that holds a reference value
(In the same way that i32 is a type, and 5 is a value)
Those are two different variables (bindings), that happen to have the same name (but are of no relation to one another).
It's the type that's different. At first, it is of type &i32, which is a reference. But I wouldn't say the variable is a reference, I'd say it stores or holds a reference.
The second time the type is i32. Still, the variable isn't a number, it stores a number.
Note that there are two distinct variables named r1. They are not the same variable.let isn't an assignment, it's a declaration that creates a fresh variable.
let ns = &a;
let nx = &mut b;
let mut ms = &c;
let mut mx = &mut d;
nx and mx are exclusive references, or mutable references. ns and nx are shared references. Some do call these "immutable references", but that can be misleading as it is possible to mutate through a shared reference in some cases. Here's an article on the topic.
I would call ms and mxmut bindings, and ns and nx non-mut bindings. The distinction doesn't come up in conversation much; the compiler will tell you when you need to add or remove mut. And as mentioned, adding mut to every binding doesn't change the semantics of a compiling program.