Rust’s basic notes on ownership

Time:2021-12-7

Write in front

Ownership system is the most unique and attractive feature of rust. Rust also relies on this feature to achieve his biggest goal: memory security. All rust developers should understand it in detail.
What a strong flavor of translation. Indeed, I mainly rely on official documents (written clearly and in detail) to learn rust. This series of articles are my notes on learning rust, not completely translating official documents, but most of the content comes from official documents, but with a lot of my own understanding, thinking and summary, these notes are also the most basic concepts, There is no in-depth research for the time being. I hope you can read the official manual more when reading the article. Criticism, correction and supplement are welcome.

Ownership

A great feature of rust is that it can check out most security risks during compilation, which avoids the fact that, like C language, everything is OK during compilation and a segment fault occurs during runtime, which makes people unclear. Therefore, rust needs a mechanism to ensure that these problems occur during compilation. This is the powerful ownership system, which includes three parts:

  • Ownership
  • Borrowing
  • Lifetime

(as will be mentioned later), this thing is really not easy to understand. You have to take your time.


When a variable binding is declared, that is, the variable has the ownership of the corresponding memory area. When the variable exceeds the scope, the memory it points to will be released.
Of course, we can assign it to other bindings, like this:

//the vector allocates space on the heap
let v=vec![1, 2, 3];
let v2=v;

If you call the original variable after the new binding, you will get the following error:

error: use of moved value: `v`

The reason is let V2 = V; This statement transfers the memory area pointed to by V to v2. The reason for the error is that the original words of the official document are:

When we move v to v2, it creates a copy of that pointer, for v2. Which means that there would be two pointers to the content of the vector on the heap. It would violate Rust’s safety guarantees by introducing a data race. Therefore, Rust forbids using v after we’ve done the move.

In other words, there are two pointers pointing to the memory area. In order to avoid data competition, rust does not allow the source variable after move to be used.

Here is a question: if V2 exceeds its scope, can v be called?

let v = vec![1,2,3];    
{
    let v2 = v;
}
println!("v[0] is {} ",v[0]);

The result is still an error:

error: use of moved value: `v`

That is, when V2 exceeds its scope, V2 will not return the ownership of its corresponding memory area.

The same problem can be encountered for functions:

fn take(v: Vec<i32>) {
    // what happens here isn’t important.
}

let v = vec![1, 2, 3];
take(v);
println!("v[0] is: {}", v[0]);

Still encounter such problems

error: use of moved value: `v`

You may feel that some variable bindings are not like this, for example:

let v = 1;
let v2 = v;
println!("v is {}",v);
println!("v2 is {}",v2);

This code can be output normally.
This is because x is of type I32, which implements the copy feature. The original words of the official document are:

In this case, v is an i32, which implements the Copy trait. This means that, just like a move, when we assign v to v2, a copy of the data is made. But, unlike a move, we can still use v afterward. This is because an i32 has no pointers to data somewhere else, copying it is a full copy.

The reason why the above code has no problem is that it is a complete copy, and it is copied together with the data. There is no problem that two pointers point to the same memory area, let alone data competition. Therefore, this code has no rust security mechanism, which is naturally allowed. This is different from move.

If you want to use v after V2, you can use the following method:

let v = vec![1,2,3];    
let v2 = v;
println!("y[0] is {} ",y[0]);
let v = v2; // Return ownership
println!("v[0] is {} ",v[0]);

Is this syntax troublesome? Is there any way to make V2 return ownership after it goes beyond the scope? Yes, let’s take a look at the concept of borrow.


Continuous update