RUST 每日一省:借用&引用

        借用的概念是规避所有权规则的限制。进行借用时,你不会获取值的所有权,只能临时地拥有对这个变量读或写的权限。在下边例子中,为了在length()函数之后,继续使用变量s1,我们不得不将已经传入length()的s1,再返回来;这是由于s1在传入length()时,所有权也传递到函数内部,在main()中,已经无法继续使用s1。这个时候,我们可以使用借用,让他变得简单。

fn main() {
    let s1 = String::from("hello world");
    let (s2, len) = length(s1);
    println!("The length of '{}' is {}.", s2, len);
} 
fn length(s: String) -> (String, usize) {
    let length = s.len(); 
    (s, length)
}

        在 Rust 中,我们可以通过两种方式借用值。使用&符号或者&mut符号表示。 前者表示只读借用, 后者表示可读写借用。下边length()和change()两函数,分别代表不可变借用和可变借用的实际用例——可以在不进行所有权转移的情况下,使用变量;

fn main() {
    let mut s1 = String::from("hello world");
    {
        let len = length(&s1);
        println!("The length of '{}' is {}.", s1, len);
    }
    {
        change(&mut s);
        println!("The s1: {}", s1);
    }
} 

fn length(s: &String) -> usize { //在类型之前使用运算符&,创建一个不可变借用。
    s.len()
}//s在这会被释放掉。

fn change(s: &mut String) { //使用&mut 运算符对s进行可变借用
    s.push_str("!!!");
}//s在这会被释放掉。

引用&借用

        引用是一种语法,本质上是Rust提供的一种指针语义; 引用是基于指针的实现, 它与指针的区别是,指针保存的是其指向内存的地址, 而引用可以看作某块内存的别名,使用它需要满足编译器的各种安全检查规则。 引用也分为不可变引用和可变引用。 使用&符号进行不可变引用, 使用&mut符号进行可变引用。

        在所有权系统中, 借用是对引用行为的描述。引用&x也可称为x的借用, 通过&操作符来完成所有权租借。 既然是借用所有权, 那么引用并不会造成绑定变量所有权的转移。

        借用在编译后,实际上就是一个普通的指针, 唯一的区别是语义层面上的。它的作用是告诉编译器, 它对指向的这块内存区域没有所有权。使用借用,与直接使用拥有所有权的值一样自然, 而且还不需要转移所有权。

借用规则

  • 借用指针的生命周期不能超过其指向的变量。 因为借用指针只能临时地拥有对这个变量读或写的权限, 没有义务管理这个变量的生命周期。如果它的生命周期超过其指向的变量,指向的变量被释放,那么它将指向一个被释放的值,变成悬空指针。
  • 如果只有&型借用指针, 那么能同时存在多个&型; 如果存在&mut型借用指针, 那么只能存在一个&mut型,即不允许其他引用(&型借用或&mut借用)在该作用域下指向相同的值。因为&mut型是一种独占性借用;
  • &mut型借用只能指向本身具有mut修饰的变量, 对于只读变量,不可以有&mut型借用。

       借用规则类似于读写锁,即同一时刻只能拥有一个写锁,或者多个读锁,不允许写锁和读锁同时出现。这是为了避免数据竞争,保障数据一致性。Rust在编译时完成借用规则的检查,这样可以有效地避免运行时出现死锁等问题。

        我们可以通过花括号来创建一个新的作用域范围。这就使我们可以创建多个可变引用,当然,这些可变引用不会同时,这个可以看上边第二段代码,&和&mut同时出现。

猜你喜欢

转载自blog.csdn.net/xq723310/article/details/130421367