Study Rust Bible analysis - Rust learn-6 (quote and borrow, Slice)

Citation and Borrowing

In the last article, we talked about the problem of ownership transfer-scope consumption. We should know that such problems are very common and very common, and we hope that we can still use variables after they are passed into the scope, or even use Variables after some processing in scope, so references yield

In the book, it is very clear to separate reference from borrowing, thinking:
reference: reference (reference) is like a pointer, because it is an address, from which we can access the data stored in the address belonging to other variables. Unlike pointers, references are guaranteed to point to a valid value of a particular type.
Borrowing: We call the act of creating a reference borrowing

However, in my opinion, they do not need to be distinguished, because I think they are all behaviors of obtaining the value of a variable without preempting its ownership, so I will not distinguish them clearly in my article

The following is a process of returning scope_area after borrowing the value of a by reference:

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


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

Let's understand the same (I won't separate it here), scope_area borrows the value of a, performs a series of processing, and finally returns the processing result of the value of a, and returns it to the variable a

It’s like: a person rents your car, after going out to play, he does a maintenance on the car and finally returns the car to you. The car is still your car, but the car has undergone some “retouching”

Reference confusion (use of both mutable and immutable references)

This problem is caused by the use of variable references while using immutable references. Of course, the order is still the same!

as follows:

fn main() {
    
    
    let mut s = String::from("hello");
    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    let r3 = &mut s; // 有问题
    println!("{}, {}, and {}", r1, r2, r3);
}

Let's understand: both r1 and r2 are unchanged, and we regard them as read-only. When two people are reading a very rigorous article, r3 is variable to modify the article, and this is a problem. , if immutable references and mutable references are processed at the same time, which one should we prevail? Do you go to work after you have changed it, or do you not change it?

deal with

How to deal with reference disorder? We think that if the reference is consumed, there will be no problem. Yes, consuming the reference at the right time can avoid this problem.

fn main() {
    
    
    let mut s = String::from("hello");

    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    println!("{} and {}", r1, r2);
    // 此位置之后 r1 和 r2 不再使用

    let r3 = &mut s; // 没问题
    println!("{}", r3);
}

Or we can also take different scopes to distinguish

fn main() {
    
    
    let mut s = String::from("hello");

    {
    
    
        let r1 = &s; // 没问题
        let r2 = &s; // 没问题
    }

    let r3 = &mut s; // 没问题
    println!("{}", r3);
}

dangling quote

In languages ​​with pointers, it is easy to mistakenly generate a dangling pointer by retaining a pointer to it when freeing memory, meaning that the memory it points to may have already been allocated to another holder.
Let's look at the following examples:

fn dangle() -> &String {
    
    
    let s = String::from("hello");
    &s
}

fn main() {
    
    
    let a = dangle();
}

In this example, a variable s is declared in the function, and then the reference of s is returned. In main, a gets the return value of this function, so can it really get it? In fact, a cannot get the return value
because the variable s in the function has been released after the function is executed, so the natural reference to s is also empty, even the original object referenced is gone, and the reference is naturally meaningless
. What about changes? In fact, it would be nice to return String directly instead of &String. This operation is actually a transfer of ownership!
Equivalent to:

fn main(){
    
    
//当然这样写肯定不是正确的我只是表达一下
	let a = let s = String::from("hello");
}

Slice string slice reference (&str)

First understand string slicing. We know that strings are composite types. Composite types can determine one of the elements (or unit units) through indexes. Slicing is to intercept the complete String. Adding a [起始索引..终止索引]reference is to get the value without getting it. ownership. Suddenly, I wonder if it is very familiar, yes it is &str!

fn main() {
    
    
    let a = String::from("this is a test");
    let b = &a[1..6];
    println!("{}",b);
}

If you have a string slice, you can pass it directly. If you have a String, you can pass a slice of the entire String or a reference to the String. This flexibility takes advantage of deref coercions, defining a function that takes a String slice instead of a String reference makes our API more general without losing any functionality

Guess you like

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