• 2.5 References & Borrowing


    Here is how you would define and use a calculate_length function that has a reference to an object as a parameter instead of taking ownership of the value:

    [root@itoracle test]# cargo new references
         Created binary (application) `references` package
    [root@itoracle test]# cd references/
    [root@itoracle references]# vim src/main.rs 
    fn main() {
        let s1 = String::from("wa ka ka ");
        let _len = get_length(&s1);
        println!("The length of '{}' is {}",s1,_len);
    }
    
    fn get_length(ss: &String) -> usize{
        ss.len()
    }
    [root@itoracle references]# cargo run
       Compiling references v0.1.0 (/usr/local/automng/src/rust/test/references)                                             
        Finished dev [unoptimized + debuginfo] target(s) in 7.50s                                                            
         Running `target/debug/references`
    The length of 'wa ka ka ' is 9

     These ampersands are references, and they allow you to refer to some value without taking ownership of it. 

    The &s1 syntax lets us create a reference that refers to the value of s1 but does not own it. Because it does not own it, the value it points to will not be dropped when the reference goes out of scope.

    Likewise, the signature of the function uses & to indicate that the type of the parameter s is a reference. Let’s add some explanatory annotations:

    fn get_length(s: &String) -> usize { // s is a reference to a String
        s.len()
    } // Here, s goes out of scope. But because it does not have ownership of what
      // it refers to, nothing happens.

    如果使用ownership方式求字符串长度,s1的可用范围就立即变化,引用的方式不会使变量可用范围发生变化,以下是ownership的实现方式

    fn main() {
        let s1 = String::from("wa ka ka ");
        let _len = get_length(s1); //基于ownership 时s1 move到了方法中,作用域虽然没有变,但后续不能再使用s1变量了
        //   println!("The length of '{}' is {}",s1,_len);
        println!("The length is {}",_len);
    }
    
    fn get_length(ss: String) -> usize{
        ss.len()
    }

    Mutable References

    fn main() {
        let mut s1 = String::from("wa ka ka ");
        change(&mut s1);
        println!("s1={}",s1);
    }
    
    fn change(my_str: &mut String){
        my_str.push_str("!!!");
    }
    [root@itoracle references]# cargo run
       Compiling references v0.1.0 (/usr/local/automng/src/rust/test/references)                                             
        Finished dev [unoptimized + debuginfo] target(s) in 1.06s                                                            
         Running `target/debug/references`
    s1=wa ka ka !!!

    First, we had to change s to be mut. Then we had to create a mutable reference with &mut s and accept a mutable reference with some_string: &mut String.

    But mutable references have one big restriction: you can have only one mutable reference to a particular piece of data in a particular scope. This code will fail:

    下面代码是错误的

    let mut s = String::from("hello");
    
    let r1 = &mut s;
    let r2 = &mut s;
    
    println!("{}, {}", r1, r2);

    This restriction allows for mutation but in a very controlled fashion. It’s something that new Rustaceans struggle with, because most languages let you mutate whenever you’d like.

    The benefit of having this restriction is that Rust can prevent data races at compile time. A data raceis similar to a race condition and happens when these three behaviors occur:

    • Two or more pointers access the same data at the same time.
    • At least one of the pointers is being used to write to the data.
    • There’s no mechanism being used to synchronize access to the data.

    Data races cause undefined behavior and can be difficult to diagnose and fix when you’re trying to track them down at runtime; Rust prevents this problem from happening because it won’t even compile code with data races!

    As always, we can use curly brackets to create a new scope, allowing for multiple mutable references, just not simultaneous ones:

    let mut s = String::from("hello");
    
    {
        let r1 = &mut s;
    
    } // r1 goes out of scope here, so we can make a new reference with no problems.
    
    let r2 = &mut s;

    下一次的可变引用,要建立在上一次的引用“不可用”的基础的上,下面的做法也可以

    这里的 不可用,是指作用域可能还没消失,但运行时不可调用了,代码中不可使用了

    fn main() {
        let mut s1 = String::from("wa ka ka ");
        change(&mut s1);
        println!("s1={}",s1);
    
        {
            let _r1 = &mut s1;
        } // r1 goes out of scope here, so we can make a new reference with no problems.
    
        let _r2 = &mut s1;
        change(&mut s1); //_r2在可变s1被第二次引用时不可再使用,后面不能再对_r2使用了
    
    }
    
    fn change(my_str: &mut String){
        my_str.push_str("!!!");
    }

     对于可变引用,如果代码中有一个以上的地方引用,那就表示至少有两处地方可以对该变量修改,不符合rust可变变量只能有一处地方可修改的规则,编辑阶段就会报错。

    一个可变变量同一作用域中只能有一处可用引用,新的引用生效时,已有引用失效,后续无法再次使用。

    将已经用过一次的可变引用以方法参数传递时,之前对该可变变量的引用自动失效,只要后续不再使用之前的引用变量,代码可以正常运行;

    如果是直接将可变引用第二次赋值到新变量,则是编译阶段报错。

    fn main() {
        let mut s1 = String::from("wa ka ka ");
        change(&mut s1);
        println!("s1={}",s1);
    
        {
            let _r1 = &mut s1;
        } // r1 goes out of scope here, so we can make a new reference with no problems.
    
        let _r2 = &mut s1;
        change(&mut s1);
        let r3 = &s1; // no problem
        let r4 = &s1; // no problem
        let r5 = &mut s1; //前面还有引用(_r2)未失效,这里会报错
        println!("{},{}",r3,r4);
    }
    
    fn change(my_str: &mut String){
        my_str.push_str("!!!");
    }
    error[E0502]: cannot borrow `s1` as mutable because it is also borrowed as immutable                                     
      --> src/main.rs:14:14                                                                                                  
       |                                                                                                                     
    12 |     let r3 = &s1; // no problem                                                                                     
       |              --- immutable borrow occurs here                                                                       
    13 |     let r4 = &s1; // no problem                                                                                     
    14 |     let r5 = &mut s1;                                                                                               
       |              ^^^^^^^ mutable borrow occurs here                                                                     
    15 |     println!("{},{}",r3,r4);                                                                                        
       |                      -- immutable borrow later used here                                                            
                                                                                                                             
    error: aborting due to previous error                                                                                    
                                                                                                                             
    For more information about this error, try `rustc --explain E0502`.                                                      
    error: Could not compile `references`.     
  • 相关阅读:
    How to configure security of ActiveMQ ?
    CentOS 搭建 nginx + tomcat
    25个 Git 进阶技巧
    写给Git初学者的7个建议
    my links
    Shell scripts to Create a local dir base on the time.
    81For全栈技术网
    一款可视化的在线制作H5
    在线制作h5
    在线制作h5——上帝的礼物
  • 原文地址:https://www.cnblogs.com/perfei/p/10492149.html
Copyright © 2020-2023  润新知