面试题答案
一键面试Rust中共享引用(&T)和可变引用(&mut T)的规则
- 共享引用(&T)规则
- 可以有多个共享引用同时指向同一个数据。
- 共享引用只能读取数据,不能修改数据。这确保了在同一时间内,多个部分的代码可以安全地访问数据,而不用担心数据被意外修改,从而避免数据竞争问题。
- 可变引用(&mut T)规则
- 在同一时间内,只能有一个可变引用指向特定的数据。
- 可变引用允许对数据进行修改。这种限制保证了在任何时刻,只有一段代码可以修改数据,防止数据竞争。
- 可变引用和共享引用不能同时存在。也就是说,当有一个可变引用时,不能有其他共享引用或可变引用指向同一数据;当有共享引用时,不能创建可变引用。
适用场景举例
- 优先选择共享引用的场景
- 数据读取操作:当你只需要读取数据,例如遍历集合进行统计或者显示数据时,使用共享引用。例如:
fn sum_numbers(numbers: &[i32]) -> i32 {
let mut sum = 0;
for num in numbers {
sum += num;
}
sum
}
在这个函数中,numbers
是共享引用,因为我们只是遍历并读取这个数组中的元素来计算总和,不需要修改数组。
- 多线程安全的数据访问:在多线程环境中,如果数据不需要被修改,使用共享引用可以安全地在多个线程间共享数据,因为共享引用不会引发数据竞争。
2. 优先选择可变引用的场景
- 数据修改操作:当你需要修改数据时,例如向数组中添加元素,或者修改结构体的字段。例如:
fn add_number(numbers: &mut Vec<i32>, num: i32) {
numbers.push(num);
}
在这个函数中,numbers
是可变引用,因为我们需要修改 Vec
,向其中添加新的元素。
- 原地算法:一些算法需要在原始数据上进行修改,而不是创建新的数据副本,这种情况下可变引用是必要的。例如排序算法通常会在原数组上进行排序:
fn sort_numbers(numbers: &mut [i32]) {
numbers.sort();
}
这里 numbers
是可变引用,因为 sort
方法会修改数组的顺序。