【Rust 中级教程】 13 引用与借用(1)

176 阅读4分钟

0x00 开篇

本篇文章将介绍 Rust 的引用,这也是一种缓和所有权的方法。我们已经在前面见过这个 & 这个符号,尤其是在使用字符串字面量的时候,我们会使用 &str。那么本篇文章将正式的认识一下它 &本篇文章的阅读时间大约 8 分钟

0x01 引用(Reference)与借用(Borrow)

当我们在使用某些方法或者函数时,并不想把所有权转移到方法或者函数内部,Rust 则提供了一个新的概念——借用。借用的意思就是每次要执行某个方法或者函数,我把变量先借给你用一下,等你执行结束,你还要还回来。有句俗话不是说好借好还,再借不难吗。另外,变量在借用的时候,起码要显而易见吧,让编译器和读者都要明白,所以我们就使用 & 操作符。简单来讲, “引用”表示在代码层面可见的语法,而“借用”则表示代码在这个过程中的整个行为流程

0x02 可变引用和共享引用

再来了解两个概念——共享引用和可变引用。

  • 共享引用(Shared Reference):直译为共享引用,只能读取不能修改。很多文章也称其为“不可变引用”。我们可以为一个值创建多个共享引用。如 &T 就叫做 T 的共享引用。
fn main() {
    // 1.共享引用
    // String类型
    let m = String::from("rust");
    // 引用:&m 表示 对x的共享引用
    let n = &m;
    println!("m = {}, n = {}", m, n);
}
// 运行结果
//  x = 888, y = 888
  • 可变引用(Mutable Reference):可以读取且可以修改。共享应用使用操作符 &mut 。如 &mut T 就叫做 T 的可变引用。当某个值存在可变引用时,你将不能拥有该值的任何其它引用。
fn main() {
    let mut a = String::from("rust");
    let b = &mut a;
    b.push_str(" is so easy!");
    println!("{}", b);
}
// 运行结果
// rust is so easy!

【重要】:共享引用在编译时执行多读(Multiple Readers)的检查规则,可变引用在编译时执行单写(Single Writer)的检查规则。

  • ****如果某个值存在共享引用,该值将被锁定,无法被修改,即便是该值的所有者也将禁止修改它。
  • 如果某个值存在可变引用,则该引用将拥有排他读写权。在这个可变引用的存续期间,对应值的所有者都将无法使用。

0x03 解引用

显式解引用

既然存在引用,那必然需要相反的操作——解引用。在 Rust 中,引用是通过 & 来显式创建的,那么解引用也需要显式使用 * 操作符。

fn main() {
    let x = 888;
    let y = &x;
    println!(" x = {}, y = {}", x, *y);
}
// 运行结果
//  x = 888, y = 888
隐式解引用

当使用 . 操作符来调用一些方法时,Rust 会对齐进行隐式解引用。除此之外,必须使用 & 和 * 来追随引用。

fn main() {
    let mut a = String::from("rust");
    (&mut a).push_str(" is so easy!");
    println!("{}", a);
}
// 运行结果
// rust is so easy!

上面的代码:(&mut a).push_str(" is so easy!");等价于 a.push_str(" is so easy!");。其实从push_str方法的源码(如下:)我们也可以看到,传递的是一个 &mut self 可变引用值,这里就是隐式解引用。

push_str 方法源码(string.rs)

pub fn push_str(&mut self, string: &str) {
 self.vec.extend_from_slice(string.as_bytes())
}

0x04 引用的内存分析

本篇文章介绍的引用其实存的仅仅是一个地址,这个地址就指向了真正的数据。大家可以通过断点自己看下堆栈信息。

图片

0x05 小结

本篇文章简单介绍了引用,算是一个开篇。务必要记住并且理解借用行为的规则。

  • 任何引用的作用域必须小于其引用原值的作用域
  • 同一作用域中不能同时存在可变引用和共享引用,允许同时有多个共享引用或者仅有一个可变引用
  • 可变引用的存续期间,无法使用对应值,即便是对应值的所有者也都将无法使用