一、引用借用,是什么、为什么、怎么用
所有权上篇我们已经讨论过了,所以这篇我们讨论Rust的引用借用
1、引用借用 是什么?
Rust 通过借用(Borrowing) 这个概念来达成上述的目的,获取变量的引用 ,称之为借用(borrowing)。
其实就是指针 ,在Rust叫 做借用,只不过Rust的借用会比指针的使用更严格一点。
2、为什么要有引用借用
所有权很强大,避免了内存的不安全性,但是也带来了一个新麻烦 : 总是把一个值传来传去来使用它。 传入一个函数,很可能还要从该函数传出去,结果就是语言表达变得非常啰嗦,幸运的是,Rust 提供了新功能解决这个问题。
3、怎么用
我们先来看一个简单的例子
rust
fn main() {
let x = 5;
let y = &x;//获取了不可变变量x的引用,y本身是不可变的变量
assert_eq!(5, x);
assert_eq!(5, *y);//获取引用所指向地址的值,和其它语言类似,通过*来获取
}
这段代码中,y获取了不可变变量x的引用。
那么y 是 不可变 引用,在这个不可变引用一词中,"不可变 "指的是该引用不可以修改 所指向的值!一定要主要这个区别。
y 也是一个不可变变量 ,这里的不可变,指的是y不可以指向别的变量 ,或者是说不可以修改y的值,要和不可变引用进行区别
通过一段代码和图来进一步理解
rust
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也是一个不可变引用 ,我们不可以修改该引用指向的值,如果我们要修改,就会报错
rust
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
bash
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、可变引用
那我们想通过引用来修改引用指向的值该怎么办,这时候就有可变引用
rust
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
这样就能完成修改。
这里一共有关键的两步
- 声明 s 是可变类型
- 其次创建一个可变的引用 &mut s 和接受可变引用参数 some_string: &mut
String 的函数。注意是&mut
接下来我们聊一下可变引用的一些使用注意事项
可变引用同时只能存在一个
rust
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
这段代码会报错
bash
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 第一个借用在这里使用
可变引用与不可变引用不能同时存在
rust
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // 大问题
println!("{}, {}, and {}", r1, r2, r3);
bash
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真好玩(手动狗头)
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")
}