1.为什么使用引用
为什么需要引用呢,当你想用某个变量,但是并不想得到他的所有权的时候,可以用引用。
2.如何使用
- 参考的类型是&String,而不是String
- &符号就表示引用:允许你引用某些值而不取得其所有权
fn main(){
let s1 = String::from("hello");
let get_len = cal_len(&s1);
println!("{} 字符串的长度是:{}",s1,get_len);
}
fn cal_len(s: &String) -> usize {
s.len()
}
把引用作为函数参数的这个行为叫借用
3.如何通过引用修改变量的原始值
现在如果想要在函数中修改引用的值,还是不可以的,因为现在这个引用还是不可变的。
我们需要这样
fn main(){
let mut s1 = String::from("hello");
let get_len = cal_len(&mut s1);
println!("{} 字符串的长度是:{}",s1,get_len);
}
fn cal_len(s: &mut String) -> usize {
s.push_str(",hdat");
s.len()
}
让变量和引用都是可变的,现在,就可以通过引用修改到变量的原始值了。
4.可变引用需要注意
- 可变引用有一个重要的限制:在特定的作用域内,对某一块数据,只能有一个可变的引用。
- 这样可以在编译时防止数据竞争。
- 会发生数据竞争的三种行为:
- 两个或多个指针同时访问同一个数据
- 至少有一个指针用于写入数据
- 没有使用使用任何机制来同步多数据的访问
但是,如果就想使用多个可变引用,也是可以的,可以通过创建新的作用域来实现
fn main() {
let mut s = String::from("hello");
{
let s1 = &mut s;
}
let s2 = &mut s;
}
一旦允许多个可变引用存在,那就不能同时拥有一个不可变的引用
多个不变的引用是可以的,但是多个可变的引用中不能存在一个不可变的引用
5.悬空引用
- 悬空指针: 一个指针引用了内存中的某个地址,然而这块内存可能已经释放并分配给其他人使用了。
- rust中,编译器可以保证引用永远都不是悬空引用。
fn main() {
let r = dangle();
}
// 因为出了这个函数,s就被释放了,所以返回的引用指向的是一块被释放的存储空间
fn dangle() -> &String {
let s = String::from("hello");
&s
}
这个时候,编译的时候就会报错,防止这种错误的发生。
6.引用的规则
- 在任何时刻,只能满足以下一个条件:
- 一个可变的引用
- 多个不可变的引用
- 引用必须一直有效,别让其所指向的位置被释放了