Rust入门-引用借用

发布于:2024-04-20 ⋅ 阅读:(20) ⋅ 点赞:(0)

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

所有权上篇我们已经讨论过了,所以这篇我们讨论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);//获取引用所指向地址的值,和其它语言类似,通过*来获取
}

这段代码中,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()
}

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

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

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

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

fn main() {
    let s = String::from("hello");

    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}
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) {
  |        

3、可变引用

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

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

这样就能完成修改。

这里一共有关键的两步

  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);

这段代码会报错

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 第一个借用在这里使用

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

let mut s = String::from("hello");

let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // 大问题

println!("{}, {}, and {}", r1, r2, r3);
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 不可变借用在这里使用

注意,引用的作用域 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")
}