面试题答案
一键面试Rust借用规则核心要点
- 同一作用域内,可变借用只能有一个:
- 这意味着在给定的代码块中,不能同时有多个对同一数据的可变引用。例如:
let mut num = 5; let r1 = &mut num; // 下面这行代码会报错,因为已经有了一个可变借用r1 // let r2 = &mut num; *r1 = 6; println!("{}", num);
- 不可变借用可以有多个,但不能与可变借用同时存在:
- 可以有多个不可变引用同时访问数据,但当有可变引用时,不可变引用就不允许存在。例如:
let num = 5; let r1 = # let r2 = # println!("{} {}", r1, r2); // 下面这行代码会报错,因为已经有不可变借用r1和r2,不能再创建可变借用 // let r3 = &mut num;
- 借用的生命周期必须小于等于被借用对象的生命周期:
- 借用的数据不能在被借用对象销毁后继续存活。例如:
fn main() { let result; { let num = 5; result = # // 这里会报错,因为num的生命周期在这个块结束,result的生命周期长于num } // println!("{}", result); }
在并发编程中防止数据竞争
- 数据竞争的定义:数据竞争发生在多个线程同时访问同一内存位置,其中至少有一个是写操作,并且没有适当的同步机制。
- Rust借用规则防止数据竞争的原理:
- 由于同一时间要么只有不可变借用(允许多个),要么只有一个可变借用,这就保证了同一时间不会有多个线程对同一数据进行写操作,或者读操作与写操作同时进行。
- 例如,假设有两个线程,线程1尝试可变借用数据进行写操作,线程2尝试不可变借用数据进行读操作。根据借用规则,这是不允许的,Rust编译器会在编译时就检测到这个错误。
- 下面是一个简单的多线程并发代码示例:
use std::thread; fn main() { let mut data = String::from("hello"); let handle = thread::spawn(|| { // 这里如果要对data进行操作,需要可变借用 // 但在主线程中data已经是可变的,所以这里会报错 // let mut new_data = &mut data; // new_data.push_str(", world"); // println!("{}", new_data); }); // 主线程中对data进行操作 data.push_str(", rust"); handle.join().unwrap(); println!("{}", data); }
- 在上述代码中,如果尝试在子线程中获取对
data
的可变借用,由于主线程中已经有对data
的可变借用,编译器会报错,从而防止了数据竞争。这确保了在并发编程中,对共享数据的访问是安全的,避免了数据竞争问题。