RUST是移动语义与copy trait

在 Rust 中,实现了 Copy trait 的类型会被自动复制而不是移动。这些类型通常具有以下特点:

  1. 大小固定且在编译时已知

  2. 数据完全存储在栈上

  3. 浅复制和深复制效果相同

  4. 基本类型(Primitive Types)

所有基本类型都实现了 Copy:

rust 复制代码
fn main() {
    // 整数类型
    let x: i8 = 1;
    let y: u8 = 2;
    let a: i16 = 3;
    let b: u16 = 4;
    let c: i32 = 5;      // 默认整数类型
    let d: u32 = 6;
    let e: i64 = 7;
    let f: u64 = 8;
    let g: i128 = 9;
    let h: u128 = 10;
    let i: isize = 11;   // 平台相关,指针大小
    let j: usize = 12;   // 平台相关,指针大小
    
    // 浮点数类型
    let k: f32 = 3.14;
    let l: f64 = 2.718;  // 默认浮点数类型
    
    // 布尔类型
    let m: bool = true;
    
    // 字符类型
    let n: char = '🦀';
    
    // 所有这些类型都实现了 Copy
    let x2 = x;  // 复制,不是移动
    println!("{} {}", x, x2);  // 两者都有效
}
  1. 复合类型(Compound Types)

某些复合类型也实现了 Copy:

rust 复制代码
fn main() {
    // 元组:当所有元素都实现 Copy 时
    let t1: (i32, f64) = (42, 3.14);
    let t2 = t1;  // 复制
    println!("{:?} {:?}", t1, t2);  // 两者都有效
    
    // 数组:当元素类型实现 Copy 且大小固定时
    let arr1: [i32; 3] = [1, 2, 3];
    let arr2 = arr1;  // 复制
    println!("{:?} {:?}", arr1, arr2);
    
    // 以下会编译错误,因为 String 没有实现 Copy
    // let bad_tuple: (String, i32) = ("hello".to_string(), 42);
    // let bad_tuple2 = bad_tuple;  // 错误:String 没有实现 Copy
}
  1. 自定义类型的 Copy 实现

3.1 自动派生 Copy

rust 复制代码
#[derive(Copy, Clone, Debug)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Copy, Clone, Debug)]
struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8,
}

fn main() {
    let p1 = Point { x: 10, y: 20 };
    let p2 = p1;  // 复制,因为 Point 实现了 Copy
    
    println!("p1: {:?}", p1);  // 仍然有效
    println!("p2: {:?}", p2);
    
    let c1 = Color { r: 255, g: 0, b: 0, a: 255 };
    let c2 = c1;  // 复制
    
    println!("c1: {:?}", c1);
    println!("c2: {:?}", c2);
}

3.2 不能自动实现 Copy 的情况

rust 复制代码
// 以下类型不能实现 Copy:
// 1. 包含非 Copy 类型
// 2. 可变引用
// 3. 堆分配的类型

#[derive(Debug)]
struct Person {
    name: String,  // String 没有实现 Copy
    age: u8,
}

impl Clone for Person {
    fn clone(&self) -> Self {
        Person {
            name: self.name.clone(),  // 需要显式克隆
            age: self.age,            // u8 是 Copy,自动复制
        }
    }
}

// 不能派生 Copy,因为包含 String
// #[derive(Copy, Clone)]  // 编译错误!

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    
    let p2 = p1.clone();  // 必须显式克隆
    // let p3 = p1;       // 这是移动,p1 不再有效
}
  1. Copy 与 Clone 的区别
rust 复制代码
#[derive(Debug)]
struct Example {
    data: i32,
}

impl Clone for Example {
    fn clone(&self) -> Self {
        println!("克隆被调用!");
        Example { data: self.data }
    }
}

// 实现 Copy 需要先实现 Clone
impl Copy for Example {}

fn demonstrate_copy_vs_clone() {
    let e1 = Example { data: 42 };
    
    // Copy 类型:自动复制
    let e2 = e1;  // 这里调用的是 Copy,不是 Clone
    println!("e1: {:?}, e2: {:?}", e1, e2);
    
    // 显式调用 clone 方法
    let e3 = e1.clone();  // 这里会调用 Clone
    println!("e3: {:?}", e3);
}

fn main() {
    demonstrate_copy_vs_clone();
}
  1. Copy trait 的约束

要为一个类型实现 Copy,必须满足以下条件:

  1. 类型的所有字段都必须实现 Copy
  2. 类型不能实现 Drop trait
rust 复制代码
#[derive(Debug)]
struct NonCopyable {
    data: Vec<i32>,  // Vec 没有实现 Copy
}

// 下面的实现会导致编译错误:
// impl Copy for NonCopyable {}  // 错误:NonCopyable 包含非 Copy 字段

#[derive(Debug)]
struct Resource {
    id: i32,
}

impl Drop for Resource {
    fn drop(&mut self) {
        println!("释放资源 {}", self.id);
    }
}

// 下面的实现会导致编译错误:
// impl Copy for Resource {}  // 错误:Resource 实现了 Drop
  1. 完整示例:自定义 Copy 类型
rust 复制代码
use std::fmt;

#[derive(Debug, Copy, Clone)]
struct Complex {
    real: f64,
    imag: f64,
}

impl Complex {
    fn new(real: f64, imag: f64) -> Self {
        Complex { real, imag }
    }
    
    fn add(self, other: Complex) -> Complex {
        Complex {
            real: self.real + other.real,
            imag: self.imag + other.imag,
        }
    }
}

impl fmt::Display for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.2} + {:.2}i", self.real, self.imag)
    }
}

fn main() {
    let c1 = Complex::new(1.0, 2.0);
    let c2 = Complex::new(3.0, 4.0);
    
    // 由于 Complex 实现了 Copy,这里都是复制
    let c3 = c1;
    let c4 = c2;
    let sum = c3.add(c4);
    
    println!("c1 = {} (仍然有效)", c1);
    println!("c2 = {} (仍然有效)", c2);
    println!("c3 = {}", c3);
    println!("c4 = {}", c4);
    println!("c1 + c2 = {}", sum);
}
  1. 判断类型是否实现 Copy
rust 复制代码
fn is_copy<T: Copy>() {
    println!("类型 T 实现了 Copy");
}

fn check_types() {
    // 检查各种类型
    is_copy::<i32>();           // ✓
    is_copy::<f64>();           // ✓
    is_copy::<bool>();          // ✓
    is_copy::<char>();          // ✓
    is_copy::<(i32, f64)>();    // ✓
    is_copy::<[i32; 5]>();      // ✓
    
    // 下面的会编译错误:
    // is_copy::<String>();     // ✗
    // is_copy::<Vec<i32>>();   // ✗
    // is_copy::<&mut i32>();   // ✗
}

fn main() {
    check_types();
}
  1. 在泛型中约束 Copy
rust 复制代码
// 泛型函数,要求 T 实现 Copy
fn duplicate<T: Copy>(value: T) -> (T, T) {
    (value, value)
}

// 另一种写法
fn duplicate2<T>(value: T) -> (T, T)
where
    T: Copy,
{
    (value, value)
}

fn main() {
    // 这些调用都正常
    let (a1, a2) = duplicate(42);
    let (b1, b2) = duplicate(3.14);
    let (c1, c2) = duplicate('x');
    
    println!("{} {}", a1, a2);
    println!("{} {}", b1, b2);
    println!("{} {}", c1, c2);
    
    // 下面的调用会编译错误:
    // let s = String::from("hello");
    // let (s1, s2) = duplicate(s);  // 错误:String 没有实现 Copy
}
  1. Copy 类型列表总结

类别 具体类型 说明

整数 i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize 所有整数类型

浮点数 f32, f64 所有浮点数类型

布尔 bool 布尔值

字符 char Unicode 标量值

元组 (T1, T2, ...) 当所有元素都实现 Copy 时

数组 [T; N] 当 T 实现 Copy 且 N 是编译时常量时

指针 *const T, *mut T 原始指针(不安全)

函数指针 fn(T1, T2) -> R 函数指针

空类型 () 单元类型

  1. 重要例外

以下类型没有实现 Copy:

rust 复制代码
fn main() {
    // 1. String(堆分配)
    let s = String::from("hello");
    // let s2 = s;  // 移动,不是复制
    
    // 2. Vec<T>(堆分配)
    let v = vec![1, 2, 3];
    // let v2 = v;  // 移动
    
    // 3. Box<T>(堆分配)
    let b = Box::new(42);
    // let b2 = b;  // 移动
    
    // 4. &mut T(可变引用)
    let mut x = 5;
    let r = &mut x;
    // let r2 = r;  // 移动
    
    // 5. Rc<T>, Arc<T>(引用计数)
    use std::rc::Rc;
    let rc = Rc::new(42);
    // let rc2 = rc;  // 移动(增加引用计数)
}

关键记忆点:

  1. 所有基本类型(整数、浮点数、布尔、字符)都实现 Copy
  2. 堆分配的类型(String, Vec, Box)通常不实现 Copy
  3. 要自动派生 Copy,类型的所有字段都必须实现 Copy
  4. 实现了 Drop trait 的类型不能实现 Copy
  5. Copy 是标记 trait,没有方法,它依赖于 Clone trait
相关推荐
生信碱移1 天前
神经网络单细胞预后分析:这个方法直接把 TCGA 预后模型那一套迁移到单细胞与空转数据上了!竟然还能做模拟敲除与预后靶点筛选?!
人工智能·深度学习·神经网络·算法·机器学习·数据挖掘·数据分析
superman超哥1 天前
Rust 并发性能调优:线程、异步与无锁的深度优化
开发语言·后端·rust·线程·异步·无锁·rust并发性能
superman超哥1 天前
Rust Trait 对象与动态分发权衡:性能与灵活性的深度权衡
开发语言·后端·rust·rust trait·对象与动态发布·性能与灵活性
ftpeak1 天前
Burn:纯 Rust 小 AI 引擎的嵌入式物体识别之旅(一步不踩坑)
开发语言·人工智能·rust
yugi9878381 天前
MFCC特征提取与SVM训练语音识别
算法·支持向量机·语音识别
yuanmenghao1 天前
MSAC 算法详解以及与 RANSAC 对比示例
算法·自动驾驶·聚类·ransac·msac·系统辨识‘
造夢先森1 天前
常见数据结构及算法
数据结构·算法·leetcode·贪心算法·动态规划
listhi5201 天前
基于蒙特卡洛方法处理电力系统负荷不确定性的解决方案
算法
iAkuya1 天前
(leetcode)力扣100 29删除链表的倒数第 N 个结点(双指针)
算法·leetcode·链表
@卞1 天前
01_树的 dfs 序
算法·深度优先