面试题答案
一键面试面临的问题
- 所有权转移:默认情况下,当数组作为函数参数传递时,所有权会转移给函数。这意味着原数组在函数外部无法再使用,如果后续代码尝试使用原数组,会导致编译错误。例如:
fn take_array(arr: [i32; 3]) {
// 这里arr拥有数组的所有权
}
fn main() {
let my_array = [1, 2, 3];
take_array(my_array);
// 这里再使用my_array会报错,因为所有权已转移给take_array函数
// println!("{:?}", my_array);
}
- 性能损耗:如果数组较大,转移所有权意味着会进行大量数据的复制,这会带来性能开销。
优化方法
- 借用:
- 不可变借用:可以通过不可变借用的方式传递数组,这样函数可以读取数组内容,但不会获取所有权,原数组在函数调用后仍然可用。例如:
fn print_array(arr: &[i32]) {
for num in arr {
println!("{}", num);
}
}
fn main() {
let my_array = [1, 2, 3];
print_array(&my_array);
println!("{:?}", my_array);
}
- 可变借用:如果函数需要修改数组内容,可以使用可变借用。不过要注意,在同一时间只能有一个可变借用,以避免数据竞争。例如:
fn increment_array(arr: &mut [i32]) {
for num in arr.iter_mut() {
*num += 1;
}
}
fn main() {
let mut my_array = [1, 2, 3];
increment_array(&mut my_array);
println!("{:?}", my_array);
}
- 切片:在 Rust 中,使用切片
&[T]
作为函数参数是一种常见且高效的方式。切片是对数组或动态分配向量的一部分的引用,它不会获取所有权,并且切片的大小是动态的(与固定大小的数组不同),这使得函数可以处理不同长度的数组或向量。例如:
fn sum_slice(slice: &[i32]) -> i32 {
let mut sum = 0;
for num in slice {
sum += num;
}
sum
}
fn main() {
let my_array = [1, 2, 3];
let result = sum_slice(&my_array);
println!("Sum: {}", result);
}
通过上述所有权、借用和切片机制,可以优化数组在函数间传递的过程,避免性能损耗和内存安全问题。