How to understand the ownership of Rust

The ownership of

Understanding rust’s ownership mechanism will give us a deeper understanding of rust’s excellent memory management mechanism and code structure that is safer than C++.

For example in C, if we were to define a pointer object: Fun *p = do_something(), we would use the object do_otherthing(p); After do_othering is used for p, we don’t know what changes were made to p inside the function, and it happens that if the implementation of the function is very complex and p is used multiple times, it can introduce a lot of trouble to the maintenance of the program. If p is released inside the function, and the outer lexical scope is not aware of it, it will form a null pointer, and using p again in such a case will cause an error.

On this basis, C++ introduced smart Pointers to reduce the occurrence of such bugs, and the concept of ownership also emerged.

Ownership in Rust represents the following concepts:

  • Each value is managed by a variable in Rust, which is the manager of the memory.
  • Each value or each block has a point in time where there’s only one possessionThe ownership ofThe owner of.
  • Variables are released when their scope ends.
fn main(){ let mut s = String::from("hello"); s.push_str("juejin"); println! (" {:? }",s); }Copy the code

In this little piece of code, you define a String of type String, modify it, and print it. When main ends, s’s life cycle ends and is freed from memory.

The life cycle is an extension of Rust’s approach to managed ownership

If I add a line after the first line above:

let s1 = s;
Copy the code

This is because the ownership of s is transferred to S1. This is because the String type does not implement Copytrait. Implement the Copytrait type, will copy a piece of memory to the assigned variable at the time of assignment, so that two points to different memory addresses, also can coexist. Some simple variables in Rust implement the Copytrait for easy development and use. Such as numbers, Boolean, etc.

Smart Pointers

Box

There are three simple smart Pointers in Rust: Box

,Rc

, and Cell

. All three relate to ownership semantics.

First is Box, where ownership values in Rust are allocated on the stack by default. We can wrap the value around the Box pointer to allocate memory on the heap.

fn main() {let num = Box::new(1);
    let i = #
    // let k = num; Error
    let j = #
    println!("{:? }",num);
    println!("{}",i)
}
Copy the code

Since Box itself implements the Deref trait, we can get the internal value 1 by dereferencing &. Box also implements the Droptrait, which automatically destroys at the end of the scope. The destruction process frees the data on the heap, followed by the value. In the case of Box, it is important to know how much memory a type consumes at definition time, which is easy to determine with Box. The Box pointer itself is on the stack, and its data is allocated on the heap.

Rc

The Rc pointer, as the name suggests, is a reference count pointer. Rc wraps an immutable type that allows multiple references to exist at the same time, but cannot be modified internally. Rc uses the Clone () method to add references.

use std::rc::Rc;
let arr = Rc::new(vec![1.2.3]);
let arr_1 = arr.clone();
let arr_2 = Rc::clone(&arr);
Copy the code

If we need multiple references to an immutable variable, and modify. RefCell can be used.

Cell

First, internal variability. That is, multiple references are shared and exist simultaneously. Shared references can modify internal data. While the core of Rust ownership is shared immutable, the two are not in conflict. Because previously shared immutable is a compiler check at compile time, using Cell can be done by returning a copy of the wrapped value, modifying it, and replacing the old value with the new one. One requirement for Cell use is that the T in Cell

must implement the Copytrait. This also corresponds to the semantics of the previous copy.

let num = Cell::new(String::from("12"));
num.set(String::from("22"));
println!("{}",num.get());
// Error
// note: the following trait bounds were not satisfied:
// `String: Copy`
let num_1 = Cell::new(1);
num_1.set(123);
println!("{}",num_1.get());
Copy the code