一、引用与借用
1、引用
当我们需要将一个参数传入到一个函数中,并且不希望这个参数的所有权进行转移,我们就用到了引用
看一段例子:
fn main() {
let s1 = String::from("hello");
let lens = reference(&s1);
println!("{} 的长度是 {}", s1, lens); // 在这里还可以使用s 证明s的所有权还在该作用域 没有被移动
}
// 引用
fn reference(s: &String) -> usize {
s.len()
} // s1的所有权不会被丢弃
可以使用&符号来实现引用的效果,实际上some_string的内存是这样指向的:
![[Pasted image 20230824102250.png]]
函数reference的入参指向了s1的指针接着指向了s1在堆上的内容,s并没有拥有s1的所有权,只是引用了s1的数据内容。
提示:引用的数据内容默认是不可变的。
2、借用
若需要引用的数值可变,可以使用可变引用,即借用可以调整上述函数如下:
fn main() {
let mut ss = String::from("hello:");
reference_active(&mut ss);
println!("变化之后:{}", ss);
}
// 可变参数引用 借用
fn reference_active(some_string: &mut String) {
some_string.push_str("world");
}
在函数reference_active(&mut ss)调用参数时加入 &mut ,即可实现借用,但是借用有很大的限制,如果对一个参数进行借用,那么这个参数就不能被引用。
当引用同一个参数,并且借用同一个参数时,会发生错误,如下代码:
fn reference_and_borrowing(){
let mut s = String::from("hello");
// 对s进行引用
let s1 = &s;
let s2 = &s;
// 对s进行借用
let s3 = &mut s;
// 对s的引用以及借用进行使用
println!("s1 : {}, s2 : {}, s3: {}",s1,s2,s3);
}
在使用借用之后,不能对相同参数进行引用,因为在对s产生借用了之后,可能会改变s指向的堆内容,而在借用之前就已经对s进行引用了,可能会使引用的数据该变。
所以在使用完引用的数据之后,在使用借用就不会编译出错,例如:
fn reference_and_borrowing() {
let mut s = String::from("hello");
// 对s进行引用
let s1 = &s;
let s2 = &s;
// 对s的引用进行使用
println!("s1 : {}, s2 : {}", s1, s2);
// 对s进行借用
let s3 = &mut s;
// 对s的借用进行使用
println!("s3: {}", s3);
}
上述代码就会正常编译且运行,输出为:
s1 : hello, s2 : hello
s3: hello