• Rust入门-引用借用


    一、引用借用,是什么、为什么、怎么用

    所有权上篇我们已经讨论过了,所以这篇我们讨论Rust的引用借用

    1、引用借用 是什么?

    Rust 通过借用(Borrowing) 这个概念来达成上述的目的,获取变量的引用,称之为借用(borrowing)。

    其实就是指针,在Rust叫借用,只不过Rust的借用会比指针的使用更严格一点。

    2、为什么要有引用借用

    所有权很强大,避免了内存的不安全性,但是也带来了一个新麻烦: 总是把一个值传来传去来使用它。 传入一个函数,很可能还要从该函数传出去,结果就是语言表达变得非常啰嗦,幸运的是,Rust 提供了新功能解决这个问题。

    3、怎么用

    我们先来看一个简单的例子

    fn main() {
        let x = 5;
        let y = &x;//获取了不可变变量x的引用,y本身是不可变的变量
    
        assert_eq!(5, x);
        assert_eq!(5, *y);//获取引用所指向地址的值,和其它语言类似,通过*来获取
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这段代码中,y获取了不可变变量x的引用。

    那么y不可变 引用,在这个不可变引用一词中,“不可变”指的是该引用不可以修改所指向的!一定要主要这个区别。

    y也是一个不可变变量,这里的不可变,指的是y不可以指向别的变量,或者是说不可以修改y的值,要和不可变引用进行区别

    通过一段代码和图来进一步理解

    fn main() {
        let s1 = String::from("hello");
    
        let len = calculate_length(&s1);
    
        println!("The length of '{}' is {}.", s1, len);
    }
    
    fn calculate_length(s: &String) -> usize {
        s.len()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    前面这段代码,效果是这样的请添加图片描述

    通过 &s1 语法,我们创建了一个指向 s1 的引用,但是并不拥有它

    因为并不拥有这个值,当引用离开作用域后,其指向的值也不会被丢弃

    同时,&s1也是一个不可变引用,我们不可以修改该引用指向的值,如果我们要修改,就会报错

    fn main() {
        let s = String::from("hello");
    
        change(&s);
    }
    
    fn change(some_string: &String) {
        some_string.push_str(", world");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&` reference
     --> src/main.rs:8:3
      |
    8 |   some_string.push_str(", world");
      |   ^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
      |
    help: consider changing this to be a mutable reference
      |
    7 | fn change(some_string: &mut String) {
      |        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、可变引用

    那我们想通过引用来修改引用指向的值该怎么办,这时候就有可变引用

    fn main() {
        let mut s = String::from("hello");
    
        change(&mut s);
    }
    
    fn change(some_string: &mut String) {
        some_string.push_str(", world");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这样就能完成修改。

    这里一共有关键的两步

    1. 声明 s 是可变类型
    2. 其次创建一个可变的引用 &mut s 和接受可变引用参数 some_string: &mut
      String 的函数。注意是&mut

    接下来我们聊一下可变引用的一些使用注意事项

    可变引用同时只能存在一个

    let mut s = String::from("hello");
    
    let r1 = &mut s;
    let r2 = &mut s;
    
    println!("{}, {}", r1, r2);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这段代码会报错

    error[E0499]: cannot borrow `s` as mutable more than once at a time 同一时间无法对 `s` 进行两次可变借用
     --> src/main.rs:5:14
      |
    4 |     let r1 = &mut s;
      |              ------ first mutable borrow occurs here 首个可变引用在这里借用
    5 |     let r2 = &mut s;
      |              ^^^^^^ second mutable borrow occurs here 第二个可变引用在这里借用
    6 |
    7 |     println!("{}, {}", r1, r2);
      |                        -- first borrow later used here 第一个借用在这里使用
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可变引用与不可变引用不能同时存在

    let mut s = String::from("hello");
    
    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    let r3 = &mut s; // 大问题
    
    println!("{}, {}, and {}", r1, r2, r3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
            // 无法借用可变 `s` 因为它已经被借用了不可变
     --> src/main.rs:6:14
      |
    4 |     let r1 = &s; // 没问题
      |              -- immutable borrow occurs here 不可变借用发生在这里
    5 |     let r2 = &s; // 没问题
    6 |     let r3 = &mut s; // 大问题
      |              ^^^^^^ mutable borrow occurs here 可变借用发生在这里
    7 |
    8 |     println!("{}, {}, and {}", r1, r2, r3);
      |                                -- immutable borrow later used here 不可变借用在这里使用
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意,引用的作用域 s 从创建开始,一直持续到它最后一次使用的地方,这个跟变量的作用域有所不同,变量的作用域从创建持续到某一个花括号 }

    给大家一段代码看看,Rust真好玩(手动狗头)

    fn main() {
      let mut s = String::from("hello, ");
      let mut y=&mut s;
      y.push_str("world");
      println!("{}",y)
    }
    
    fn push_str(s: &mut String) {
      s.push_str("world")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    Mybatis 快速入门之 动态sql和分页
    SpringBoot学习(1) —— 初始化SpringBoot开发环境
    [Linux]下制作简易myshell
    【19】c++设计模式——>桥接模式
    python在循环中捕获异常后继续执行下一轮
    【数据结构与算法】线性结构和非线性结构
    flutter 自定义加载中间页 loading 菊花组件的封装
    linux系统java环境变量的下载与安装
    苹果电脑提高工作效率alfred 5中文
    MasaFramework -- 更优雅的获取配置信息
  • 原文地址:https://blog.csdn.net/vince1998/article/details/137966137