一、引用借用,是什么、为什么、怎么用
所有权上篇我们已经讨论过了,所以这篇我们讨论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");
}
这样就能完成修改。
这里一共有关键的两步
- 声明 s 是可变类型
- 其次创建一个可变的引用 &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")
}