作者:小洲相册居士 | 来源:互联网 | 2024-11-02 13:43
引用与借用是编程中重要的概念,涉及数据类型的管理和访问方式。引用允许在不获取所有权的情况下使用值,而解引用则通过解引用运算符`*`来访问引用所指向的实际数据。本文深入解析了引用与借用的机制,并通过具体的代码示例展示了其在实际编程中的应用,帮助读者更好地理解和掌握这些关键概念。
引用与借用
引用是一种数据类型
& 符号就是引用
解引用(dereferencing)
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // &s1 创建了一个指向 s1 的引用,但不拥有s1
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize { //参数为&String,不是String
s.len()
} // s 离开了作用域。但因为它并不拥有引用值的所有权,所以什么也不会发生
s 为 s1 的引用,s 指向 s1 (指针?
借用(borrowing)
可变引用
&mut string
就为一个可变引用类型
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
该代码可以正常编译
限制:在同一时间,对于某一特定的数据,只能有一个可变引用
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
该代码不能编译
这个限制的好处是 Rust 可以在编译时就避免数据竞争(出现数据竞争的情况时,rust在编译时就会报错
- 数据竞争(data race)类似于竞态条件,它可由这三个行为造成:
- 两个或更多指针同时访问同一数据
- 至少有一个指针被用来写入数据
- 没有同步数据访问的机制
可以创建新的作用域(通过大括号),以允许非同时拥有多个可变引用
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1 在这里离开了作用域,所以可以创建一个新的引用 r2
let r2 = &mut s;
另一个限制:不可以同时有一个可变引用与一个不可变引用
let mut s = String::from("hello");
let r1 = &s; // 不可变引用
let r2 = &s; // 不可变引用
let r3 = &mut s; // 可变引用,不可以
println!("{}, {}, and {}", r1, r2, r3);
该代码不可以编译
悬垂引用(Dangling References)
悬垂指针(dangling pointer),即一个指针引用了内存的某个地址,但这块内存可能已经事发并分配给其他人使用了
在 Rust 中编译器可以确保引用永远也不会变成悬垂状态
- 当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello"); // s 在离开函数(离开作用域)后,就失效了
&s //但对 s 的引用 &s 作为返回值返回了
//即对 s 的引用 &s 就指向了一个被释放的内存地址
}
该代码不可以编译
引用的规则(总结
- 在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用
- 引用必须一直是有效的