代码实现
// 定义结构体
struct MyStruct {
data1: i32,
data2: Box<String>,
}
// 函数1:创建并返回MyStruct实例
fn create_struct() -> MyStruct {
MyStruct {
data1: 42,
data2: Box::new(String::from("Hello, World!")),
}
}
// 函数2:接收MyStruct实例并处理
fn process_struct(s: MyStruct) {
println!("data1: {}", s.data1);
println!("data2: {}", s.data2);
}
fn main() {
let my_struct = create_struct();
process_struct(my_struct);
// 这里my_struct已经转移到process_struct函数中,不能再使用my_struct
}
Box指针与普通指针在所有权语义上的区别
- 所有权:
- Box指针:Box拥有其所指向数据的所有权。当Box离开作用域时,它会自动释放其所指向的数据,从而确保内存安全。例如在
create_struct
函数中创建的Box<String>
,当MyStruct
实例离开create_struct
函数作用域时,Box<String>
会自动释放其分配的堆内存。
- 普通指针:普通指针(如
*const T
或*mut T
)不拥有所有权。它们只是指向内存位置,不会自动管理所指向数据的生命周期和内存释放。如果使用普通指针,程序员需要手动管理内存分配和释放,这容易导致内存泄漏等问题。
- 内存管理:
- Box指针:Rust的内存管理系统通过Drop trait来管理Box。当Box被销毁时,其实现的Drop trait中的
drop
方法会被自动调用,从而释放堆上的数据。在上述代码中,当process_struct
函数结束时,MyStruct
实例被销毁,其中的Box<String>
也会自动释放内存。
- 普通指针:使用普通指针时,由于没有所有权语义,程序员需要自己编写代码来确保内存的正确释放。例如在C/C++中使用
delete
(对于new
分配的内存),如果忘记调用delete
,就会造成内存泄漏。
- 可移动性:
- Box指针:Box是可移动的,这意味着Box实例可以在函数间传递,将所有权转移给另一个函数。如上述代码中
create_struct
返回MyStruct
实例(其中包含Box
),将所有权转移到main
函数中,然后main
函数又将其所有权转移到process_struct
函数。
- 普通指针:普通指针虽然也可以在函数间传递,但不会涉及所有权的转移。普通指针传递的只是内存地址,而不会改变数据的所有权状态。