面试题答案
一键面试- 移动语义详细行为:
Complex
结构体实例:- 当执行
let c = Complex { data: vec![1, 2, 3] };
时,在栈上为c
分配空间,c
是Complex
结构体的实例。Complex
结构体本身只包含一个指向堆上Vec<i32>
的指针(以及长度和容量信息)。 - 当调用
process_complex(c);
时,c
被移动到process_complex
函数中。这意味着c
在主函数中不再有效,所有权被转移到process_complex
函数的参数c
上。主函数中的c
变量在移动后不能再被使用,如果尝试使用会导致编译错误。
- 当执行
- 内部
Vec<i32>
:Vec<i32>
存储在堆上。当Complex
结构体实例c
被创建时,Vec<i32>
在堆上分配内存来存储[1, 2, 3]
。- 当
c
被移动到process_complex
函数中时,堆上Vec<i32>
的所有权也随着Complex
结构体实例的移动而转移。Vec<i32>
所占用的堆内存并没有被复制,只是所有权发生了改变。process_complex
函数中的c
参数现在拥有对堆上Vec<i32>
的唯一所有权。
- 避免移动
Complex
实例的方法:- 使用引用:
- 可以修改
process_complex
函数,使其接受Complex
结构体的引用。例如:
- 可以修改
- 使用引用:
struct Complex {
data: Vec<i32>
}
fn process_complex(c: &Complex) {
// 函数体可以通过引用访问 Complex 实例的数据
println!("Data: {:?}", c.data);
}
fn main() {
let c = Complex { data: vec![1, 2, 3] };
process_complex(&c);
// 这里 c 仍然有效,因为只是传递了引用,没有发生移动
}
- 使用
Clone
特性:- 如果
Complex
结构体及其内部的Vec<i32>
实现了Clone
特性(Vec<i32>
本身已经实现了Clone
特性),可以克隆Complex
实例并传递克隆后的实例。例如:
- 如果
struct Complex {
data: Vec<i32>
}
impl Clone for Complex {
fn clone(&self) -> Complex {
Complex { data: self.data.clone() }
}
}
fn process_complex(c: Complex) {
println!("Data: {:?}", c.data);
}
fn main() {
let c = Complex { data: vec![1, 2, 3] };
process_complex(c.clone());
// 这里 c 仍然有效,因为传递的是克隆后的实例
}
这种方法会在堆上复制 Vec<i32>
的数据,相比传递引用会消耗更多的内存和时间,所以在性能敏感的场景下需要谨慎使用。