Rust language from entry to pit - (5) Rust ownership


insert image description here

0 import

It mainly introduces the knowledge of Rust ownership, involving the scope of variables, memory release mechanism, moving, cloning, referencing and other knowledge, a lot of knowledge is the unique mechanism of Rust language.


1. Ownership

Ownership has the following three rules:

- Every value in Rust has a variable called its owner.
- There can only be one owner at a time.
- When the owner is not in the scope of the program, the value will be deleted.

{
    
    
    // 在声明以前,变量 s 无效
    let s = "runoob";
    // 这里是变量 s 的可用范围
}
// 变量范围已经结束,变量 s 无效

2. Memory and allocation

Most programming languages ​​have functions for managing memory:

1. Languages ​​such as C/C++ mainly manage memory manually, and developers need to manually apply for and release memory resources. However, in order to improve development efficiency, as long as it does not affect the realization of program functions, many developers do not have the habit of releasing memory in time. Therefore, the way of manually managing memory often leads to waste of resources, and it is easy to forget about memory release, resulting in memory leaks.
2. Programs written in the Java language run in a virtual machine (JVM), and the JVM has the function of automatically reclaiming memory resources. But this method often reduces runtime efficiency, so the JVM will reclaim as few resources as possible, which will also make the program occupy a large memory resource.
3. Ownership is a novel concept for most developers. It is a syntax mechanism designed by the Rust language for efficient use of memory. The concept of ownership is a concept born to allow Rust to more effectively analyze the usefulness of memory resources during the compilation phase to achieve memory management.
4. The setting of ownership seems strange. In fact, it is essentially forbidden at the language level that the same variable data will have multiple variable references. Once it is passed as a parameter, the ownership will be moved (Move). Or borrow (Borrow). Assigning to another mutation automatically relinquishes ownership. It fundamentally eliminates data sharing conflicts in concurrent scenarios.
5. Rust data types can be divided into basic data types and other variable data types (variable length such as String).
Basic data types include these:
all integer types, such as i32, u32, i64, etc.
Boolean type bool, the value is true or false.
All floating point types, f32 and f64.
Character type char.
Only tuples (Tuples) containing the above types of data.

Basic data are generally defined on the stack, and others are on the heap. Where is the data? , which Rust automatically releases whenever ownership is lost


3. Move and clone

3.1. Mobile

The following code:

    //基本数据在栈中定义,交互数据是直接复制的,通过移动复制
    let x = 5;
    let y = x;
    println!("{}, {}",x,y);

	//其他数据在堆中交互
	let s1 = String::from("hello");
	let s2 = s1;                // 为了确保安全,在给 s2 赋值时 s1 已经无效了
	println!("{}, world!", s1); // 错误!s1 已经失效

3.2. Clone

Rust will try to reduce the running cost of the program as much as possible, so by default, the data with a large length is stored in the heap, and the data interaction is performed by moving. But if you need to simply copy the data for other use, you can use the second interactive method of data - cloning.

    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}, s2 = {}", s1, s2);

This will result in two separate data sets.


4. Quote and lease

4.1. Citation

Reference (Reference) is a concept familiar to C++ developers. If you are familiar with the concept of pointers, you can think of it as a kind of pointer. In essence, "reference" is the indirect access method of variables.

fn main() {
    
    
    let s1 = String::from("hello");
    let s2 = &s1;
    println!("s1 is {}, s2 is {}", s1, s2);
}

1. When the value of a variable is referenced, the variable itself is not considered invalid. Because the "reference" does not copy the value of the variable in the stack;
2. The reference will not acquire the ownership of the value. References can only borrow (Borrow) ownership of values. The reference itself is also a type and has a value, which records the location of other values, but the reference does not have ownership of the pointed value;

fn main() {
    
    
    let s1 = String::from("hello");
    let s2 = &s1;
    let s3 = s1;
    println!("{}", s2);
}
//注意 因为 s2 租借的 s1 已经将所有权移动到 s3,所以 s2 将无法继续租借使用 s1 的所有权。如果需要使用 s2 使用该值,必须重新租借,如下

fn main() {
    
    
    let s1 = String::from("hello");
    let mut s2 = &s1;
    let s3 = s1;
    s2 = &s3;        // 重新从 s3 租借所有权
    println!("{}", s2);
}

3. The leased ownership cannot modify the value of the owner. Since the reference does not have ownership, even if it leases ownership, it only enjoys the right to use.
4. Compared with immutable references, mutable references do not allow multiple references, but immutable references do.

fn main() {
    
    
    let s1 = String::from("run");
    let s2 = &s1;
    println!("{}", s2);
    s2.push_str("oob"); // 错误,禁止修改租借的值
    println!("{}", s2);
}
//当然加上 mut表示可变变量时候,是允许修改的
fn main() {
    
    
    let mut s1 = String::from("run");
    // s1 是可变的

    let s2 = &mut s1;
    // s2 是可变的引用

    s2.push_str("oob");
    println!("{}", s2);
}

4.1. Hanging references

In C++, it is: in a programming language with a pointer concept, it refers to a pointer that does not actually point to a data that can be accessed (note that it is not necessarily a null pointer, and may also be a released resource) , this is not allowed in Rust.
Typically, a local variable is defined in a function, and the return value of the function is a reference, which is the case when a local variable reference is returned.

5. Variables in functions

5.1 Parameter variables

The variable release mechanism in the function is the same as that introduced above, pay attention to the following.

fn main() {
    
    
    let s = String::from("hello"); // s 被声明有效
    takes_ownership(s); // s 的值被当作参数传入函数, 所以可以当作 s 已经被移动,从这里开始已经无效
    let x = 5;          // x 被声明有效
    makes_copy(x);      // x 的值被当作参数传入函数
                        // 但 x 是基本类型,依然有效
                        // 在这里依然可以使用 x 却不能使用 s
} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放

fn takes_ownership(some_string: String) {
    
     // 一个 String 参数 some_string 传入,有效
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    
    // 一个 i32 参数 some_integer 传入,有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放

5.2, return value variable

The ownership of the variable used as the return value of the function will be moved out of the function and returned to the place where the function was called, instead of being directly invalidated.

fn main() {
    
    
    let s1 = gives_ownership(); // gives_ownership 移动它的返回值到 s1
    let s2 = String::from("hello"); // s2 被声明有效
    let s3 = takes_and_gives_back(s2);// s2 被当作参数移动, s3 获得返回值所有权
} // s3 无效被释放, s2 被移动, s1 无效被释放.
fn gives_ownership() -> String {
    
    
    let some_string = String::from("hello"); // some_string 被声明有效
    return some_string; // some_string 被当作返回值移动出函数
}
fn takes_and_gives_back(a_string: String) -> String {
    
     
    // a_string 被声明有效
    a_string  // a_string 被当作返回值移出函数
}

Guess you like

Origin blog.csdn.net/ljsant/article/details/131349775