Computer programs must manage the memory resources they use at run time.
Most programming languages have the ability to manage memory:
Languages such as CUniverse + mainly manage memory manually, and developers need to manually apply for and release memory resources. However, in order to improve the development efficiency, as long as it does not affect the implementation of program functions, many developers do not have the habit of releasing memory in time. So the way of managing memory manually often results in a waste of resources.
The program written in Java language runs in the virtual machine (JVM), and JVM has the function of automatically reclaiming memory resources. But this approach often reduces runtime efficiency, so JVM will recycle as few resources as possible, which will also make the program take up more memory resources.
Ownership is a novel concept for most developers, and it is the syntax mechanism designed by the Rust language to use memory efficiently. The concept of ownership is developed to enable Rust to analyze the usefulness of memory resources more effectively during the compilation phase in order to achieve memory management. There are three rules for ownership: Each value in Rust has a variable called its owner. There can be only one owner at a time. This value is deleted when the owner is not in the scope of the program. These three rules are the basis of the concept of ownership. Next, we will introduce concepts related to the concept of ownership. We use the following program to describe the concept of variable scope: A variable scope is an attribute of a variable that represents the feasible domain of the variable and is valid by default from declaring the variable to the end of the variable’s domain. If we define a variable and assign it a value, the value of that variable exists in memory. This situation is very common. But if the length of the data we need to store is uncertain (such as a string entered by the user), we cannot specify the length of the data at the time of definition, and we will not be able to make the program allocate a fixed length of memory space for data storage during the compilation phase. Some people say that allocating as much space as possible can solve the problem, but this method is very uncivilized. This needs to provide a mechanism for the program to apply for memory while the program is running-heap. All the “memory resources” in this chapter refer to the memory space occupied by the heap. Where there is allocation, there is release, and programs cannot occupy a certain memory resource all the time. Therefore, the key factor to determine whether resources are wasted is whether resources are released in a timely manner. Let’s write the sample string program in C language equivalent: Obviously, there is no call in Rust This mechanism seems simple: it just helps programmers add a function call that frees resources in the right place. But this simple mechanism can effectively solve one of the most troublesome programming problems in history. There are two main ways for variables to interact with data: Move and Clone: Multiple variables can interact with the same data in different ways in Rust: This program binds the value 5 to the variable x, then copies the value of xand assigns it to the variable y. There will now be two values of 5 in the stack. The data in this case is of the “basic data” type and does not needto be stored in the heap, and the “move” mode of the data in the stack iscopied directly, which does not take longer or more storage space. The basic data types are as follows: All integer types, such as Boolean type All floating point types Character type A tuple that contains only the above types of data. But if the interactive data is in the heap, it is a different situation: The first step is to produce a The situation in the second step is slightly different (this is not entirelytrue, it is only for comparative reference): As shown in the figure: two As we said earlier, when a variable is out of range, Rust automatically calls the free resource function and cleans up the variable’s heap memory. But So the actual situation is: S1 exists in name only. Rust reduces the cost of running the program as much as possible, so by default, longer data is stored in the heap and the data is exchanged in a mobile manner. But if you need to simply make a copy of the data for other use, you can use the second way to interact with the data-cloning. Running result: Here is a real copy of the “hello” in the heap, so Of course, cloning is only used when replication is needed, since it takes more time to replicate data. This is the most complicated case for variables. How do you safely handle ownership if you pass a variable to another function as an argument to the function? The following program describes how the ownership mechanism works in this case: If you pass a variable into a function as an argument, it has the same effect as moving. The ownership of the variable that is treated as the return value of the function will be moved out of the function and returned to the place where the function is called, rather than being invalidly released directly. Reference is a concept that C++ developers are familiar with. If you are familiar with the concept of pointer, you can think of it as a pointer. In essence, “reference” is the indirect access to variables. Running result: The & operator can take a reference to a variable. When the value of a variable is referenced, the variable itself is not considered invalid. Because reference does not copy the value of the variable in the stack: Function arguments are passed in the same way: Running result: The reference does not take ownership of the value. Reference can only lease (Borrow) the ownership of values. The reference itself is also a type and has a value that records the location of other values, but the reference does not have ownership of the specified value: This procedure is incorrect: because This procedure is correct. Since the reference does not have ownership, even if it rents ownership, it only has the right to use it (which is the same as renting a house). Attempts to modify data using leased rights will be blocked: In this program, Of course, there is also a variable lease, just like you rent a house, if the property stipulates that the owner can modify the structure of the house, and the owner also declares this right in the contract when renting, you can redecorate the house: There will be no problem with this procedure. We use Mutable references do not allow multiple references compared to immutable references except for permissions, but immutable references can: This program is incorrect because s is referenced by multiple variables. Rust’s design of variable references is mainly based on the consideration ofdata access collisions in the concurrent state, which is avoided during thecompilation phase. Since one of the necessary conditions for data access collisions is that thedata is written by at least one user and read or written by at least one other user at the same time, it is not allowed to be referenced again when avalue is variably referenced. This is a concept with a different name, and if you put it in a programming language with a pointer concept, it refers to a pointer that doesn’t actually point to data that can actually be accessed (note, it’s not necessarily a null pointer, it could also be a resource that has been released). They are like ropes that lose hanging objects, so they are called”hanging references”. A “dangling reference” is not allowed in the Rust language, and if so, thecompiler will find it. Here is a typical case of overhanging: Obviously, along with 7.11.1. Ownership rule #
7.11.2. Variable range #
{
//Invalid variable s before declaration
Lets="runoob";
//Here is the available range of variable s
}
//Variable range has ended, variable s is invalid
7.11.3. Memory and allocation #
{
char *s = strdup("runoob");
free(s); // Release s resources
}
free
function to release the resources of the string s (I know this is not the correct way to write in C because “runoob” is not in the heap, so let’s assume it is). The reason why Rust does not explicitly release the step is that when the variable range ends, the Rust compiler automatically adds the step of calling the release resource function. 7.11.4. The way variables interact with data #
7.11.5. move #
let x = 5;
let y = x;
i32
、
u32
、
i64
, etc.
bool
with a value of
true
or
false
.
f32
and
f64
.
char
.let s1 = String::from("hello");
let s2 = s1;
String
object with a value of “hello”.Where “hello” can be thought of as data of uncertain length, which needs to be stored in the heap.
String
object in the stack, each
String
objects have a pointer to the “hello” string in the heap. In giving
s2
when assigning, only the data in the stack is copied, and thestring in the heap is still the original string.
s1
and
s2
if both are released, the “hello” in the heap areais released twice, which is not allowed by the system. In order to ensure safety, give
s2
when assigning values
s1
is no longer effective.That’s right. I’m putting
s1
value assigned to the
s2
later,
s1
will no longer be available for use. The following procedure is wrong:let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1); // Error! S1 has expired

7.11.6. Clone #
Example #
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
}
s1 = hello, s2 = hello
s1
and
s2
Each is bound to a value, and when released, it is treated as two resources. 7.11.7. Ownership mechanism involving functions #
Example #
Fn main(){
Lets=String:: from ("hello");
//S declared valid
Take_ Ownership (s);
//The value of s is passed into the function as a parameter
//So it can be considered that s has been moved and is no longer valid from here on
Let x=5;
//X declared valid
Make_ Copy (x);
//The value of x is passed into the function as a parameter
//But x is the basic type and still valid
//You can still use x here, but not s
}//Function ended, x invalid, followed by s. However, s has been moved, so it does not need to be released
Fn takes_ Ownership (some_string: String){
//A String parameter some_ String passed in, valid
Println! ({} ", some_string);
}//Function ended, parameter some_ String is released here
Fn makes_ Copy (some_integer: i32){
//An i32 parameter some_ Incoming integer, valid
Println! ({} ", some_integer);
}//Function ended, parameter some_ Integer is a basic type and does not need to be released
7.11.8. Ownership mechanism of function return value #
Example #
Fn main(){
Let s1=gifts_ Ownership();
//Gives_ Ownership moves its return value to s1
Let s2=String:: from ("hello");
//S2 declared valid
Let s3=takes_ And_ Gives_ Back (s2);
//S2 is moved as a parameter, and s3 obtains ownership of the return value
}//s3 is invalid and released, s2 is moved, and s1 is invalid and released
Fn gifts_ Ownership() ->String{
Let some_ String=String:: from ("hello");
//Some_ String declared valid
Return some_ String;
//Some_ String is moved out of the function as a return value
}
Fn takes_ And_ Gives_ Back (a_string: String) ->String{
//A_ String declared valid
A_ String//a_ String is used as a return value to move out of the function
}
7.11.9. Citation and lease #
Example #
fn main() {
let s1 = String::from("hello");
let s2 = &s1;
println!("s1 is {}, s2 is {}", s1, s2);
}
s1 is hello, s2 is hello

Example #
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
The length of 'hello' is 5.
Example #
fn main() {
let s1 = String::from("hello");
let s2 = &s1;
let s3 = s1;
println!("{}", s2);
}
s2
leased
s1
ownership has been moved to
s3
, so
s2
will not be able to continue to lease
s1
ownership of. If you need to use the
s2
with this value, you must re-lease:Example #
fn main() {
let s1 = String::from("hello");
let mut s2 = &s1;
let s3 = s1;
s2 = &s3; // Renting ownership from s3
println!("{}", s2);
}
Example #
fn main() {
let s1 = String::from("run");
let s2 = &s1;
println!("{}", s2);
s2.push_str("oob"); // Error, it is prohibited to modify the rental value
println!("{}", s2);
}
s2
try to modify,
s1
is blocked and the ownership of the lease cannot modify the owner’s value.Example #
fn main() {
let mut s1 = String::from("run");
// S1 is variable
let s2 = &mut s1;
// S2 is a variable reference
s2.push_str("oob");
println!("{}", s2);
}
&mut
modifies a variable reference type.Example #
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
7.11.10. Dangling References #
Example #
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
dangle
at the end of a function, the value of itslocal variable itself is not treated as a return value and is released. However, its reference is returned, and the value pointed to by this reference can no longer be determined, so it is not allowed.