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

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

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 引用的内存分析


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


0a2653c851af460fa595bd959398a8f1.png


0x05 小结


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

  • 任何引用的作用域必须小于其引用原值的作用域
  • 同一作用域中不能同时存在可变引用和共享引用,允许同时有多个共享引用或者仅有一个可变引用
  • 在可变引用的存续期间,无法使用对应值,即便是对应值的所有者也都将无法使用
相关文章
|
2月前
|
Rust 安全 编译器
Rust中的生命周期与借用检查器:内存安全的守护神
本文深入探讨了Rust编程语言中生命周期与借用检查器的概念及其工作原理。Rust通过这些机制,在编译时确保了内存安全,避免了数据竞争和悬挂指针等常见问题。我们将详细解释生命周期如何管理数据的存活期,以及借用检查器如何确保数据的独占或共享访问,从而在不牺牲性能的前提下,为开发者提供了强大的内存安全保障。
|
3月前
|
设计模式 Rust JavaScript
【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数
【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数
37 0
|
2月前
|
Rust 安全 编译器
Rust中避免常见错误:悬挂引用与生命周期不匹配
本文深入探讨了Rust编程语言中常见的两个内存管理错误:悬挂引用和生命周期不匹配,并提供了避免这些错误的实用方法。我们将详细解释这两种错误的来源,并通过示例展示如何在Rust中通过正确的生命周期标注和借用规则来避免它们,从而确保代码的内存安全性。
|
4月前
|
存储 Rust 安全
Rust 中的引用与借用
Rust 中的引用与借用
|
5月前
|
Rust 安全 编译器
Rust 基础入门 —— 2.3.所有权和借用 (二)
同一时刻,你只能拥有要么一个可变引用, 要么任意多个不可变引用 引用必须总是有效的 贴一个体验不错的学习链接恰饭:学习链接
43 0
|
5月前
|
存储 Rust 安全
Rust 基础入门 —— 2.3.所有权和借用
写在前面的序言 因为我们这里实际讲述的内容是关于 内存安全的,所以我们最好先复习一下内存的知识。
25 0
|
5月前
|
Rust 安全 JavaScript
Rust教程初识
当然,它们都有编译然后执行可执行程序的用法。应当有编译后改名的方式,不然那也太不coooooooooooool了。
43 0
|
9月前
|
存储 消息中间件 Rust
Rust极简教程
Rust是一门赋予每个人构建可靠且高效软件能力的编程语言。可靠主要体现在安全性上。其高效不仅限于开发效率,它的执行效率也是令人称赞的,是一种少有的兼顾开发效率和执行效率的语言。Rust 语言由 Mozilla 开发,最早发布于 2014 年 9 月。Rust 的编译器是在 MIT License 和 Apache License 2.0 双重协议声明下的免费开源软件。
243 0
Rust极简教程
|
12月前
|
存储 Rust JavaScript
Rust:为什么不能在同一个结构体中存储一个值和对该值的引用?(修改版)
基本把下面问题这个搞明白,就能彻底明白 Rust 语言的生命周期是怎么回事了。简而言之,生命周期不会改变你的代码,是你的生命控制生命周期,而不是生命周期在控制你的代码。换言之,生命周期是描述性的,而不是规定性的。
135 0
|
Rust 编译器
Rust 中级教程 第17课——引用的 lifetime(2)
Rust 中级教程 第17课——引用的 lifetime(2)
Rust 中级教程 第17课——引用的 lifetime(2)