可能遇到的数据一致性问题
- 数据重复释放:当结构体实现
Copy
trait 且包含Vec
时,由于Copy
是浅拷贝,多个结构体实例会共享Vec
内部的堆内存。当这些实例先后析构时,会多次释放同一块堆内存,导致运行时错误,例如 double free
错误。
- 数据修改不一致:如果一个实例修改了
Vec
中的数据,其他通过浅拷贝得到的实例的Vec
也会发生相同变化,这可能不符合预期,破坏了数据的独立性和一致性。
示例代码
#[derive(Copy, Clone)]
struct MyStruct {
data: Vec<i32>
}
fn main() {
let s1 = MyStruct { data: vec![1, 2, 3] };
let s2 = s1; // 浅拷贝
// s1和s2共享同一Vec数据
println!("s1: {:?}", s1.data);
println!("s2: {:?}", s2.data);
s1.data.push(4);
// s2的data也会改变,这可能不符合预期
println!("s1 after push: {:?}", s1.data);
println!("s2 after s1 push: {:?}", s2.data);
}
避免这种问题的方法
- 不实现
Copy
trait:让结构体只实现Clone
trait,手动实现深度拷贝逻辑。这样在复制时会创建全新的Vec
实例,各自独立。
- 使用
Rc
或Arc
:如果希望共享数据,可以使用Rc
(单线程)或Arc
(多线程)来管理堆内存,这样多个实例可以共享数据,但只有所有引用都消失时才会释放内存。
示例代码 - 实现Clone
trait
struct MyStruct {
data: Vec<i32>
}
impl Clone for MyStruct {
fn clone(&self) -> Self {
MyStruct {
data: self.data.clone()
}
}
}
fn main() {
let s1 = MyStruct { data: vec![1, 2, 3] };
let s2 = s1.clone(); // 深度拷贝
s1.data.push(4);
// s2的data不会改变
println!("s1 after push: {:?}", s1.data);
println!("s2 after s1 push: {:?}", s2.data);
}
示例代码 - 使用Rc
use std::rc::Rc;
struct MyStruct {
data: Rc<Vec<i32>>
}
impl Clone for MyStruct {
fn clone(&self) -> Self {
MyStruct {
data: self.data.clone()
}
}
}
fn main() {
let s1 = MyStruct { data: Rc::new(vec![1, 2, 3]) };
let s2 = s1.clone(); // 共享数据,增加引用计数
println!("s1: {:?}", s1.data);
println!("s2: {:?}", s2.data);
}