Request you to given comments on my notes on Rust. May correct the terminologies.
This is also my attempt to create material for persons who are new to programming.
In Rust, a variable is a tag to a meta-data on some data. The variable is said to own
the "data". To make language simple, we short-circuit the term variable and meta-data
and simply say variable contains data (or memory location of data)
Depending on the type, the data can be embedded in the variable, or variable contains
pointers to the memory location where data actually stored. For primitive types, the data is
stored in the variable itself.
For a complex data type such as String, complex structs, the data is stored in heap and
variables contains pointers to those data in the heap memory.
In Rust, reference or reference variable is a Special Variable which refers
(loosely we can say it points to) to the actual variable.
For example,
let i : i32 = 5 ;
Here i is a variable and holds the value 5. &i represents a reference variable pointing to i.
let j = &i ;
Here reference variable &i referencing actual variable i is assigned to j . Hence j is
also a reference variable. This reference variable j is also referencing the actual variable i.
In Rust, references can be Copied as Rust implements Copy trait for references.
In C we have pointers. If x is a pointer variable , then to access the value it contains, one
needs to de-reference using * . ..ie. *x .
In Rust, when I can use reference variable like aregular variable. Consider the following program
struct Point {
x: i32,
y: i32,
}
fn main()
{
let p1 = Point { x:5, y:5};
let r_square = r_square(&p1);
println!("Distance squared from origin is {}",r_square);
}
fn r_square(p : &Point) ->i32
{
//Even though p is a reference, I don't use
//any de-referencing operator to access the
//structure.
let r2 = (p.x) * (p.x) + (p.y) * (p.y);
r2
}
I passed a complex data type called Point ( which is defined using struct) as a reference.
In side the function that reference variable is called p .
I access the data elements of the structure through reference variable p , but I never use
any de-referencing operator.
If someone comes from C background, this is one of the differences. In C, the pointer
contains memory address.
In Rust the reference variable points to actual variable. We attempt not say it is just a pointer.
We can access the value directly from the reference variable.
Another example, consider the following code
''''''
fn main()
{
let mut s1 = String::from("Hello");
let t1 = & mut s1;
t1.push_str(" World");
println!("{}",s1);
s1.push_str(" Rust");
println!("{}",s1);
Here s1 is of type String and initialized to hold value "Hello". &s1 is a reference variable (let us forget about mut now), and assigned to t1 . (remember Copy trait for references).
Now t1 is a reference variable referring s1.
I could use t1 as if its a actual variable. In the same program, string literal " Rust" is added
to the actual variable. Note that usage are similar for both actual variable and reference variable.
Still reference variable is a reference variable.
Consider similar examples for primitive types like i32.
fn main()
{
let i : i32 = 5;
let j = &i;
let temp: i32 = j +j ;
let temp1 : i32 = j * j;
println!("{}",temp);
println!("{}",temp1);
}
Here also, j is a reference variable and we constructed an expression where j is
treated as a actual variable and not as reference variable.
Rust compiler knows how to de-reference the reference variable automatically and perform computation.
Another example with struct
#[derive(Debug)]
struct Point {
x: i32,
y : i32,
}
fn main()
{
let mut p1 = Point { x:5, y:5};
println!("{:?}",p1);
let p2 = & mut p1 ;
p2.x = 10;
p2.y = 5;
println!("{:?}",p1);
}
Here too, p2 is a reference variable referring the actual variable p1. But I can use reference variable p2 as if it is actual variable .
The point is that one cannot compare C-pointers with Rust's reference variable from the
programming perspective. Rust dont call them pointers. It is called reference or reference variable.
To understand more, consider the following code
fn main()
{
let mut i : i32 = 5;
let mut j = &i;
//Seperate variable is created
j =10 // Not possible.
j = &10;
println!("{}",i);
println!("{}",j);
println!("{}",&i);
}
In the above code j is a reference variable. j =10 is an assignment statement. That is we are trying to change the value of i to 10 through reference variable j. But Rust
encounters type mismatch error as we try to assign value 10 (i32) to a reference variable j.
The point is that you cant always treat reference variable as actual variable. The assignment i=10 is okay but Rust throws type mismatch error when j = 10.
In the statement j = &10;, what happens is value 10 is created in memory and its unnamed variable is updated (as j is mutable) to j as its reference . So j now refers
to 10 and no more refer variable i.
The question now arises in our minds , how come struct example worked when we changed the values through reference. Recall the statement in that example,
p2.x = 10 ; where p2 is a reference variable.
It subtle to note that p2 is a reference variable but p2.x is of type i32 as
defined in the Point struct !!!. Thats the reason we could assign the value
p2.x =10;
Consider the the following code.
fn main()
{
let mut i : i32 = 5;
println!("{}",i);
let j = & mut i;
//Seperate variable is created
*j = 10; //De-reference operator
println!("{}",i);
}
In the code, the value of i changed from 5 to 10 through reference variable j.
The * is a de-reference operator ( similar to C ). When I use de-reference operator,
the compiler always refers to the actual variable it points to and treat like the actual
variable even for assignment (provided type is matched).
Consider another example code with struct.
#[derive(Debug)]
struct Point {
x: i32,
y : i32,
}
fn main()
{
let mut p1 = Point { x:5, y:5};
println!("{:?}",p1);
let p2 = & mut p1 ;
p2 = Point { x:10, y:15}; //Type mismatch;
*p2 = Point { x:10, y:15};
println!("{:?}",p1);
}
Here p2 is a reference variable to the struct p1. So *p2 is like p1. Its type is same as p1 type which is Point.
In a nutshell, in Rust , reference variable can be use like a actual variable. However if we want assignment through reference vaiable then we have to use de-reference operator as illustrated above.
This is in-contrast with C pointers where pointer variable always to be de-referenced.