Study Rust Bible analysis - Rust learn-5 (ownership, powerful String)

ownership

Rust's core function (one of them) is ownership. Rust manages memory through the ownership system, and the compiler will check it according to a series of rules when compiling. If any of these rules are violated, the program will not compile. At runtime, none of the features of the ownership system will slow down the program.

stack and heap

These two concepts can be said to be very classic. In Rust, we should consider and understand these two concepts more than other languages.

Same point

Both the stack and the heap are memory available to the code at runtime

the stack

  1. All data on the stack must occupy a known and fixed size
  2. last in first out
  3. storage speed block

heap

  1. Storing data whose size is unknown at compile time or whose size may vary
  2. A memory area as large as possible is required for storage
  3. Pointer points, access is slow

ownership rules

  1. Every value in Rust has an owner.
  2. A value has one and only one owner at any one time.
  3. When the owner (variable) goes out of scope, this value will be discarded.

Please keep these three rules in mind, because if you are new to Rust, you can easily make ownership mistakes! especially the last one

scope

A scope is an area. When a variable is in its own scope, the variable is valid, and the variable is released when it is out.
Let's take a look at this example:

fn scope_area() -> &str {
    
    
    let a ="5";
    return a;
}

fn main() {
    
    
    let x = scope_area();
    println!("{}", x);
}

This code declares a variable a in the scope_area method, and then returns it. Note that here we return the &str type. In short, it is a string slice, which is a borrowing of the string. This code looks like The editor passed without syntax errors, in fact:

insert image description here
The above error occurs, saying that this requires a life cycle identifier, let's talk about why?
First of all &str is not String! It is a borrowing of String, which is a string slice. He just borrowed the String, not itself. For example, if someone borrows your pen, he cannot say that the pen is his, and he did not deal with it. Pen permissions, so he can no longer lend your pen to other people.
Then &str is the same, he can't transfer ownership to other variables, so once out of scope, he becomes invalid and released, and the new variable naturally cannot get the return value. Of course, the compiler here tells you the solution, which is to use the life cycle, but we haven't learned it now, so we don't accept it.
The correct way should be:

fn scope_area() -> String {
    
    
    let a = "5";
    return a.to_string();
}

fn main() {
    
    
    let x = scope_area();
    println!("{}", x);
}

Here we finally convert the string slice to String through to_string, so naturally there is no such problem
. Another:

fn scope_area() -> String {
    
    
    let a = "5";
    return a.to_owned();
}

fn main() {
    
    
    let x = scope_area();
    println!("{}", x);
}

We obtained the ownership of the real string a through the to_owned method. At this time, it is equivalent to someone saying that I gave you the pen, and you have the ownership of the pen. You can handle this pen at this time. How do you use the pen? Everything is your business.

String

String but not only String, this is what I think is the most accurate sentence for String in Rust, because String in Rust is not a simple char array, it has many tricks, so that in my opinion, if you understand Rust With String, you have mastered one-third of the essence of the type (you may think that one-third is very little, but after you really understand it, you will know that it is a lot of content), and then I will analyze the 'String' type in detail

String

UTF-8 encoded growable string. The string type is the most common type of string that takes ownership of the string content. It has a close relationship to its borrowed counterpart, the original str. String is stored on the heap

Create String

create empty string

let x = String::new();

Create from string literal (convert &str to String)

let a = String::from("test");

str

Called a "string slice", it is the most primitive type of string. It usually appears in its borrowed form, &str

features

  1. Immutable
  2. Content is known at compile time
  3. Hardcoded directly into the executable
  4. fast and efficient

create str

According to the following writing method, direct creation is a &str,

let a = "test";

Out of the String|str above, there are actually many types of String in Rust, such as OsString

ownership transfer

This name is just what I call it
. Let’s explain why I say this. First of all, we need to be clear about a concept. In Rust, String is also a composite type, not a simple type. Simple types refer to those that have no capacity and can be determined once the value is declared. That is: i8, u8, i32, f64, bool, etc., which were introduced earlier, but String is actually a Vector!

String source code

The following is the source code of String:

#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), lang = "String")]
pub struct String {
    
    
    vec: Vec<u8>,
}

We see that String is actually Vec<u8>u8. As for why it is u8, everyone should know that u8 is an unsigned integer with a range of 0~255. This is the effective range of the ASCLL code we often say

So we need to clarify a concept, String is a composite type, has length and capacity, can be expanded, and exists in the heap, and its reference is the pointer in the stack!

So there will be problems when we use the following code:

fn main() {
    
    
    let a = String::from("test");
    let b = a;
    println!("{}", b);
    println!("{}", a);
}

insert image description here
From the error, we can see that value borrowed here after moveafter the borrowed value is moved, that is to say, the value belonging to a is moved to b. At this time, b seizes the ownership of the String of a, causing the value of a to become invalid! We do the
same Take an example to understand: first, a has a pen, and a gave the pen to b. At this time, b has the ownership of the pen, and a no longer has the pen, so when he asked a to borrow the pen, an error occurred. This is the
ownership Problems arising from transfer
So how to solve this problem?

deep clone

In order to solve the problem of ownership transfer, we used deep cloning, we copied an identical data, so that both variables will have values, and there is no problem of ownership transfer

clone method

The same data can be cloned directly by using the clone method. Note that the premise is that the trait of Clone is implemented! Of course, you don’t know what a trait is here. If you have a foundation in other languages, then understand it as an interface, or you understand it as a rule. Implementing the rule is equivalent to having a ticket for admission, and you can enter and exit

fn main() {
    
    
    let a = String::from("test");
    let b = a.clone();
    println!("{}", b);
    println!("{}", a);
}

If you have written a structure yourself and want to clone it, is there any way? In fact, this is very simple, just to implement Clone, but in fact we will not do this, because it is time-consuming and energy-consuming, Rust provides an #[derive(Clone)]annotation to help developers directly implement clone

#[derive(Clone)]
struct test{
    
    
	//..
}

Scoped consumption (transfer of ownership - continued)

Let's look at a code first

fn scope_area(mut b: String) -> String {
    
    
    b.push_str("hello");
    return b;
}


fn main() {
    
    
    let mut a = String::from("test");
    scope_area(a);
    println!("{}", a);
}

It seems that there is no problem, but after compiling, it will tell you:
insert image description here
the same problem as in the following code appeared before

fn main() {
    
    
    let a = String::from("test");
    let b = a;
    println!("{}", b);
    println!("{}", a);
}

This shows that the essential problem of both is the same, both ownership has been transferred.
Next, let’s understand that a is a String, and there is a function that passes in a as a parameter. After a series of operations, the function execution ends. At this time When we visit a again, the value belonging to a has been preempted by the function, and a has no value. After the function performs some operations on the value of a, the function ends. At this time, the value belonging to a has not been returned, and was released and that's why

For example: you have 500 yuan, and you go to an entertainment place to spend a lot of money. In the end, you use up all the 500 yuan. The store earns your money, and the money is not yours. Isn’t this the previous ownership transfer? !

Guess you like

Origin blog.csdn.net/qq_51553982/article/details/130169455