MST
星途 面试题库

面试题:Rust中Copy trait局限性之浅拷贝问题

在Rust中,当一个类型实现了Copy trait,它会进行浅拷贝。请举例说明在使用含有复杂数据结构(比如自定义结构体中包含Vec)并实现Copy trait时,可能会遇到什么样的数据一致性问题,以及如何避免这种问题。
16.0万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

可能遇到的数据一致性问题

  1. 数据重复释放:当结构体实现Copy trait 且包含Vec时,由于Copy是浅拷贝,多个结构体实例会共享Vec内部的堆内存。当这些实例先后析构时,会多次释放同一块堆内存,导致运行时错误,例如 double free 错误。
  2. 数据修改不一致:如果一个实例修改了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);
}

避免这种问题的方法

  1. 不实现Copy trait:让结构体只实现Clone trait,手动实现深度拷贝逻辑。这样在复制时会创建全新的Vec实例,各自独立。
  2. 使用RcArc:如果希望共享数据,可以使用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);
}