Rust: A Generally View of Reference and Its Mutability

date
Feb 19, 2023
slug
rust-a-general-view-of-reference-and-its-mutability
status
Published
tags
Program
Rust
EN
type
Post
pin
0
summary
A reference (&) is used to access or change data without taking responsibility for it. This is more like a pointer in C/C++ than a reference in C++. In Rust, a reference is usually not changeable, but it can be made changeable at the top or bottom level. Automatic dereferencing is used to work out if a reference should act like an alias or a pointer.

0. Overview

Rust's most essential concept is the owner. A variable is the unique owner of some data, which means that when the variable is dropped, the data is removed from memory and cannot be recovered. This owner model provides a way to take responsibility for data in memory, preventing memory leaks and double-free errors.
If someone wants to access or modify data but doesn't want to take responsibility for it, they can use a reference (&). In Rust, a reference is more similar to a pointer in C/C++ than a reference in C++.
By default, a reference is immutable, meaning both the reference itself and the variable it refers to cannot be changed. However, when talking about a "mutable reference," there is a problem similar to the "top-level/low-level const pointer" in C/C++: which one is mutable, the reference itself or the variable it refers to?

1. The reference in Rust is the thing known as the pointer in C/C++

If we use an editor plugin with rust-analyzer, code will be displayed as follows:
The analyzer shows that the type of b is &String and c is &&String. This is similar to the *int and **int in C/C++, right?

2. Top-Level/Low-Level Mutable Reference in Rust

Let's start with C/C++. As C++ Primer explains, there are two types of const in C/C++:
The former b is a pointer to a const value a. a is not declared as a const variable, yet b treats it as such, disallowing any modifications. However, b itself is not const; it can be made to point to another const value, e.g.:
In this case, we declare b to be a low-level constant pointer.
By contrast, top-level const means that the variable to which c points may not be const, but the pointer c itself cannot be edited. We cannot make c point to another variable.
Therefore, when we consider references in C++, they are naturally top-level const.
The "location" it refers to is fixed and assigned when the reference is defined. d is simply an alias of a, nothing more.
Come back to Rust, we can define similar things like the above pointers.
Here, s3 is a low-level, mutable reference. The last line changes the value of the variable that s3 refers to, namely s1. After this, the value of s1 is “hello new world” and s3 still refers to s1.
In this case, s4 is a top-level mutable reference. The last line changes the “location” that s4 refers to.
Originally, s4 referred to s1, whose value was "hello world". After the last line was executed, s4 now referred to s2, whose value was "hello another new world".

3. Automatic Dereferencing / Deref Coercion

Things seem no different from pointers in C/C++, don't they? However, it gets more complicated because they are references, which means they must act like aliases.
It works. The outputs are the same. s3 can be treated as an alias of s1 here.
But:
If we remove the dereference sign (*), the assignment won't work. s3 cannot be used as an alias for s1; it is merely a pointer.
And in the top-level case:
We don't use * here and this time it works. We DO NOT want the compiler to treat s4 as an alias. Instead, we want it to point to another location, such as from s1 to s2.
Let's take a closer look at how the reference behaves, such as if it is an alias or a pointer. Here are the descriptions:
All primitive references have a trait called Deref. Two mechanisms, "automatic dereferencing" and "Deref coercion", can use Deref to implement "referencing" behavior.
Generally, in the following cases, reference A acts as an alias:
  • A.attribute_1
  • A.method_2(B)
  • B.method_3(A)
  • function_4(A)
Otherwise, A acts as a pointer, including:
  • A = B
  • if A == B {…}
  • match A { B => … }
 
For more information on coercion, check out the following links:

© Beautyyu言醴 2022 - 2024