#[derive(Debug, PartialEq, Clone)]是个啥?

#[derive(Debug, PartialEq, Clone)] 是个啥?

示🌰代码:
#[derive(Debug, PartialEq, Clone)]
pub enum Enum_Ex {
    String(String),
    Number(f64),
}

🗝️首先,#[derive(Debug, PartialEq, Clone)] 是一个属性。

👉属性(attributes)是用于向编译器提供关于代码段的元数据的特殊语法结构。属性可以应用于模块、crate 或其他项(如函数、结构体、枚举等),用于控制编译器的行为或包含其他类型的元数据。

属性的基本语法

属性的基本语法是使用方括号 [],并以 # 开头。根据属性的应用范围,属性可以分为外部属性(outer attribute)和内部属性(inner attribute):

外部属性 (#[attribute]):应用于紧随其后的项。

内部属性 (#![attribute]):应用于包含它的项(通常是模块或整个 crate)。

在 Rust 中,#[derive] 属性允许自动为某些特定的 trait 生成实现代码。当你在枚举或结构体上使用 #[derive] 属性时,编译器会为你提供这些 trait 的基本实现。这里的 DebugPartialEqClone 是三个可以通过 #[derive] 自动实现的 trait。

Debug

Debug trait 用于格式化输出,主要用于调试目的。当你为一个类型派生 Debug trait 时,你可以使用 {:?} 格式化占位符来打印该类型的实例,这对于快速查看实例的状态非常有用。

PartialEq

PartialEq trait 用于比较两个类型实例的相等性。派生 PartialEq 会自动实现 eq 方法,这使得你可以使用 ==!= 运算符来比较两个实例。对于结构体,如果所有字段都相等,则两个实例相等;对于枚举,相同的变体被认为是相等的。

Clone

Clone trait 允许你创建类型实例的深拷贝。派生 Clone 会自动实现 clone 方法,这意味着你可以创建一个实例的完整副本。这在需要复制数据而不是移动所有权时非常有用。

这些 trait 的自动派生实现通常足以满足基本需求,但如果你需要更复杂的行为,你也可以选择手动实现这些 trait。例如,如果你的类型包含非标准方式比较相等性的字段,你可能需要为 PartialEq 提供自定义实现。

什么时候不可以使用#[derive(Debug, PartialEq, Clone)] ❓或者说什么情况下我可以使用 #[derive()] 来为结构体自动实现 trait❓
1. 当类型的字段不支持相应的 trait 时
  • Debug:如果结构体中的某个字段类型没有实现 Debug trait,那么这个结构体就不能自动派生 Debug。例如,如果你有一个字段是某种复杂的闭包或某些自定义类型,而这些类型没有实现 Debug,那么你不能为包含这些字段的结构体派生 Debug

  • PartialEq:如果结构体中的任何字段没有实现 PartialEq,那么这个结构体也不能派生 PartialEq。这通常出现在字段类型为某些特殊函数指针或其他复杂类型时。

  • Clone:如果结构体的任何字段不支持 Clone,那么整个结构体也不能自动派生 Clone。例如,如果字段是某些特殊的资源句柄或包含原始指针,这些类型通常不支持自动克隆。

2. 性能考虑
  • Clone:如果你的类型包含大量数据或复杂的数据结构,自动派生的 Clone 实现可能会进行深拷贝,这可能导致不必要的性能开销。在这种情况下,可能需要手动实现更高效的克隆逻辑。
3. 逻辑复杂性或特定行为
  • PartialEqEq:如果你需要基于非直观的条件比较两个对象的相等性(例如,忽略某些字段或基于运行时状态),自动派生的 PartialEqEq 可能不符合你的需求。在这种情况下,你需要手动实现这些 trait,以精确控制相等性检查的行为。
4. 安全性和封装
  • 自动派生的 trait 实现可能会无意中暴露内部状态,这可能与你的封装策略相冲突。例如,如果你不希望外部代码能够比较或打印内部状态,那么自动派生 Debug 或 PartialEq 可能是不合适的。
举个🌰:
程序👇:
struct A;

#[derive(Debug)]
pub enum E {
  A(A),				//在这里用了一个自定义的结构体 A
  B(String),  
}

fn main() {
    let a = E::A(A);
    println!("{:?}",a);

    let b = E::B("B".to_string());
    println!("{:?}",b);
}
cargo build 输出👇:
error[E0277]: `A` doesn't implement `Debug`
 --> my_test\src\main.rs:5:5
  |
3 | #[derive(Debug)]
  |          ----- in this derive macro expansion
4 | pub enum E {
5 |   A(A),
  |     ^ `A` cannot be formatted using `{:?}`
A 实现 Debug trait 👇:
use std::fmt;
use std::fmt::{Display, Formatter};

pub struct A;

// 为A实现Debug trait
impl fmt::Debug for A {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Display::fmt("出来吧!我的 A", f)	// 输出定制
    }
}

#[derive(Debug)]
pub enum E {
  A(A),				//在这里用了一个自定义的结构体 A
  B(String),  
}

fn main() {
    let a = E::A(A);
    println!("{:?}",a);

    let b = E::B("B".to_string());
    println!("{:?}",b);
}
cargo run 输出👇:
A(出来吧!我的 A)
B("B")
其实还可以更简单:
#[derive(Debug)]
pub struct A;

#[derive(Debug)]
pub enum E {
  A(A),
  B(String),  
}

fn main() {
    let a = E::A(A);
    println!("{:?}",a);

    let b = E::B("B".to_string());
    println!("{:?}",b);
}
只不过输出的很简单👇:
A(A)
B("B")

🗝️很显然这样你无法召唤你的 A 出来😜😜

本站中有一部分来源于网络和媒体的内容(文章、源码、软件应用、资源附件等),并尽可能的标出参考来源、出处,本站尊重原作者的成果,若本站内容侵犯了您的合法权益时或者对转载内容有疑义的内容原作者,请书面反馈并提供确切的个人身份证明与详细资料信息在第一时间以邮件形式进行联系沟通;

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

憨七龟777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值