#traits #derive #proc-macro #macro-derive #field #procedural #macro

无 std educe

该软件包提供了旨在简化 Rust 内置特质的快速实现的进程宏。

48 个版本

0.6.0 2024 年 6 月 1 日
0.5.11 2024 年 1 月 9 日
0.5.9 2023 年 12 月 16 日
0.4.23 2023 年 9 月 9 日
0.0.7 2019 年 7 月 31 日

#63Rust 模式

Download history 87256/week @ 2024-05-04 106078/week @ 2024-05-11 92529/week @ 2024-05-18 169636/week @ 2024-05-25 196540/week @ 2024-06-01 190534/week @ 2024-06-08 173586/week @ 2024-06-15 179035/week @ 2024-06-22 182269/week @ 2024-06-29 189740/week @ 2024-07-06 187333/week @ 2024-07-13 190324/week @ 2024-07-20 182503/week @ 2024-07-27 164996/week @ 2024-08-03 182358/week @ 2024-08-10 171611/week @ 2024-08-17

735,383 每月下载量
用于 674 个软件包 (106 个直接)

MIT 许可证

410KB
8K SLoC

Educe

CI

该软件包提供了旨在简化 Rust 内置特质的快速实现的进程宏。

特性

默认情况下,该软件包支持的每个特质都将启用。您可以通过禁用默认功能来禁用所有特质,并通过将它们显式添加到 features 中来仅启用您想要使用的特质。

例如,

[dependencies.educe]
version = "*"
features = ["Debug", "Clone", "Copy", "Hash", "Default"]
default-features = false

特质

Debug

使用 #[derive(Educe)]#[educe(Debug)] 实现结构体、枚举或联合的 Debug 特质。这允许您修改您的类型、变体和字段名称。您还可以选择忽略特定字段或设置一个方法来替换 Debug 特质。此外,您还可以将结构体格式化为元组,反之亦然。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(Debug)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Debug)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
更改类型、变体或字段的名称

name 参数可以重命名类型、变体或字段。如果您将其设置为 false,则名称可以被忽略或强制显示。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug(name(Struct2)))]
struct Struct {
    #[educe(Debug(name(f)))]
    f1: u8
}

#[derive(Educe)]
#[educe(Debug(name = true))]
enum Enum {
    #[educe(Debug(name = false))]
    V1,
    #[educe(Debug(name(V)))]
    V2 {
        #[educe(Debug(name(f)))]
        f1: u8,
    },
    #[educe(Debug(name = false))]
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug)]
struct Struct {
    #[educe(Debug(ignore))]
    f1: u8
}

#[derive(Educe)]
#[educe(Debug)]
enum Enum {
    V1,
    V2 {
        #[educe(Debug(ignore))]
        f1: u8,
    },
    V3(
        #[educe(Debug(ignore))]
        u8
    ),
}
假结构体和元组

使用 named_field 参数,可以将结构体格式化为元组,将元组格式化为结构体。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug(named_field = false))]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Debug)]
enum Enum {
    V1,
    #[educe(Debug(named_field = false))]
    V2 {
        f1: u8,
    },
    #[educe(Debug(named_field = true))]
    V3(
        u8,
        #[educe(Debug(name(value)))]
        i32
    ),
}
使用其他方法处理格式化

可以使用 method 参数来替换字段的 Debug 特性的实现,从而无需为该字段的类型实现 Debug 特性。

use educe::Educe;

use std::fmt::{self, Formatter};

fn fmt<T>(_s: &T, f: &mut Formatter<'_>) -> fmt::Result {
    f.write_str("Hi")
}

#[derive(Educe)]
#[educe(Debug)]
enum Enum<T> {
    V1,
    V2 {
        #[educe(Debug(method(fmt)))]
        f1: u8,
    },
    V3(
        #[educe(Debug(method(std::fmt::UpperHex::fmt)))]
        u8,
        #[educe(Debug(method(fmt)))]
        T
    ),
}
Debug 特性或其他特性绑定的泛型参数

如果需要,泛型参数将自动绑定到 Debug 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

use std::fmt::{self, Formatter};

fn fmt<D>(_s: &D, f: &mut Formatter<'_>) -> fmt::Result {
    f.write_str("Hi")
}

#[derive(Educe)]
#[educe(Debug(bound(T: std::fmt::Debug)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(Debug(method(fmt)))]
        f1: K,
    },
    V3(
        T
    ),
}

在上面的例子中,T 绑定到 Debug 特性,但 K 没有绑定。

或者,educe 可以复制 stdderive 的行为,为每个泛型参数生成一个绑定,而不考虑它在结构体中的使用方式。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug(bound(*)))]
struct Struct<T> {
    #[educe(Debug(ignore))]
    f: T,
}

如果您不希望将特性实现部分作为您的永久公共 API 的一部分,这可能会很有用。在下面的例子中,Struct<T> 不实现 Debug,除非 T 实现。也就是说,它有一个 T: Debug 绑定,尽管目前不需要。稍后我们可能想显示 f;我们不需要通过添加绑定来做出破坏性的 API 变更。

这是 educe 0.4.x 及更早版本中 Trait(bound) 的行为。

联合体

由于我们不知道其字段在运行时的情况,联合体将格式化为 u8 切片。联合体的字段不能被忽略、重命名或使用其他方法格式化。实现是 不安全的,因为它可能会暴露未初始化的内存。

use educe::Educe;

#[derive(Educe)]
#[educe(Debug(unsafe))]
union Union {
    f1: u8,
    f2: i32,
}

克隆

使用 #[derive(Educe)]#[educe(Clone)] 来为结构体、枚举或联合体实现 Clone 特性。您可以为 Clone 特性设置一个替代的方法。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(Clone)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Clone)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
使用另一种方法进行克隆

可以使用 method 参数来替换字段的 Clone 特性的实现,从而无需为该字段的类型实现 Clone 特性。

use educe::Educe;

fn clone(v: &u8) -> u8 {
    v + 100
}

trait A {
    fn add(&self, rhs: u8) -> Self;
}

fn clone2<T: A>(v: &T) -> T {
    v.add(100)
}

#[derive(Educe)]
#[educe(Clone)]
enum Enum<T: A> {
    V1,
    V2 {
        #[educe(Clone(method(clone)))]
        f1: u8,
    },
    V3(
        #[educe(Clone(method(clone2)))]
        T
    ),
}
Clone 特性或其他特性绑定的泛型参数

如果需要,泛型参数将自动绑定到 Clone 特性。如果存在 #[educe(Copy)] 属性,它们将绑定到 Copy 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(Clone)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

trait A {
    fn add(&self, rhs: u8) -> Self;
}

fn clone<T: A>(v: &T) -> T {
    v.add(100)
}

#[derive(Educe)]
#[educe(Clone(bound(T: std::clone::Clone)))]
enum Enum<T, K: A> {
    V1,
    V2 {
        #[educe(Clone(method(clone)))]
        f1: K,
    },
    V3(
        T
    ),
}

在上面的例子中,T 绑定到 Clone 特性,但 K 没有绑定。

或者,你可以使用 educe 来复制 stdderive 的行为,通过使用 bound(*)。有关更多信息,请参阅 Debug 部分。

use educe::Educe;

trait A {
    fn add(&self, rhs: u8) -> Self;
}

fn clone<T: A>(v: &T) -> T {
    v.add(100)
}

#[derive(Educe)]
#[educe(Clone(bound(*)))]
struct Struct<T: A> {
    #[educe(Clone(method(clone)))]
    f: T,
}
联合体

请参阅 #[educe(Copy)] 属性的介绍。

复制

使用 #[derive(Educe)]#[educe(Copy)] 来为结构体、枚举或联合实现 Copy 特性。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(Copy, Clone)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Copy, Clone)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
Copy 特性或其它类型的泛型参数绑定

所有泛型参数都将自动绑定到 Copy 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(Copy, Clone)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

trait A {
    fn add(&self, rhs: u8) -> Self;
}

fn clone<T: A>(v: &T) -> T {
    v.add(100)
}

#[derive(Educe)]
#[educe(Copy, Clone(bound(T: Copy, K: A + Copy)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(Clone(method(clone)))]
        f1: K,
    },
    V3(
        T
    ),
}

请注意,对于实现了 CopyClone 特性的类型,使用自定义克隆方法可能并不完全合适。

联合体

#[educe(Copy, Clone)] 属性可用于联合。联合的字段不能使用其他方法进行克隆。

use educe::Educe;

#[derive(Educe)]
#[educe(Copy, Clone)]
union Union {
    f1: u8,
}

PartialEq

使用 #[derive(Educe)]#[educe(PartialEq)] 来为结构体、枚举或联合实现 PartialEq 特性。你也可以选择忽略特定字段或设置一个方法来替换 PartialEq 特性。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(PartialEq)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq)]
struct Struct {
    #[educe(PartialEq(ignore))]
    f1: u8
}

#[derive(Educe)]
#[educe(PartialEq)]
enum Enum {
    V1,
    V2 {
        #[educe(PartialEq(ignore))]
        f1: u8,
    },
    V3(
        #[educe(PartialEq(ignore))]
        u8
    ),
}
使用另一种方法进行比较

可以使用 method 参数来替换字段的 PartialEq 特性的实现,从而不需要为该字段的类型实现 PartialEq 特性。

use educe::Educe;

fn eq(a: &u8, b: &u8) -> bool {
    a + 1 == *b
}

trait A {
    fn is_same(&self, other: &Self) -> bool;
}

fn eq2<T: A>(a: &T, b: &T) -> bool {
    a.is_same(b)
}

#[derive(Educe)]
#[educe(PartialEq)]
enum Enum<T: A> {
    V1,
    V2 {
        #[educe(PartialEq(method(eq)))]
        f1: u8,
    },
    V3(
        #[educe(PartialEq(method(eq2)))]
        T
    ),
}
PartialEq 特性或其它类型的泛型参数绑定

如果需要,泛型参数将自动绑定到 PartialEq 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

trait A {
    fn is_same(&self, other: &Self) -> bool;
}

fn eq<T: A>(a: &T, b: &T) -> bool {
    a.is_same(b)
}

#[derive(Educe)]
#[educe(PartialEq(bound(T: std::cmp::PartialEq, K: A)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(PartialEq(method(eq)))]
        f1: K,
    },
    V3(
        T
    ),
}

在上面的情况中,T 绑定到 PartialEq 特性,但 K 没有绑定。

您可以使用 educe 来复现 stdderive 的行为,通过使用 bound(*)。有关更多信息,请参阅 Debug 部分。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq(bound(*)))]
struct Struct<T> {
    #[educe(PartialEq(ignore))]
    f: T,
}
联合体

可以使用 #[educe) 属性来处理联合类型。联合类型的字段不能与其他方法进行比较。实现是 不安全的,因为它忽略了它所使用的特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq(unsafe))]
union Union {
    f1: u8,
    f2: i32
}

Eq

使用 #[derive(Educe)]#[educe(Eq)] 来为结构体、枚举或联合类型实现 Eq 特性。您还可以选择忽略特定字段或设置一个方法来替换 PartialEq 特性。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq, Eq)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq, Eq)]
struct Struct {
    #[educe(Eq(ignore))]
    f1: u8
}

#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum {
    V1,
    V2 {
        #[educe(Eq(ignore))]
        f1: u8,
    },
    V3(
        #[educe(Eq(ignore))]
        u8
    ),
}
使用另一种方法进行比较

可以使用 method 参数来替换字段的 Eq 特性实现,从而无需实现该字段类型的 PartialEq 特性。

use educe::Educe;

fn eq(a: &u8, b: &u8) -> bool {
    a + 1 == *b
}

trait A {
    fn is_same(&self, other: &Self) -> bool;
}

fn eq2<T: A>(a: &T, b: &T) -> bool {
    a.is_same(b)
}

#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum<T: A> {
    V1,
    V2 {
        #[educe(Eq(method(eq)))]
        f1: u8,
    },
    V3(
        #[educe(Eq(method(eq2)))]
        T
    ),
}
PartialEq 特性或其它类型的泛型参数绑定

如果需要,泛型参数将自动绑定到 PartialEq 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

trait A {
    fn is_same(&self, other: &Self) -> bool;
}

fn eq<T: A>(a: &T, b: &T) -> bool {
    a.is_same(b)
}

#[derive(Educe)]
#[educe(PartialEq(bound(T: std::cmp::PartialEq, K: A)), Eq)]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(Eq(method(eq)))]
        f1: K,
    },
    V3(
        T
    ),
}
联合体

可以使用 #[educe(PartialEq(unsafe), Eq)] 属性来处理联合类型。联合类型的字段不能与其他方法进行比较。实现是 不安全的,因为它忽略了它所使用的特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq(unsafe), Eq)]
union Union {
    f1: u8,
    f2: i32
}

PartialOrd

使用 #[derive(Educe)]#[educe(PartialOrd)] 来为结构体或枚举类型实现 PartialOrd 特性。您还可以选择忽略特定字段或设置一个方法来替换 PartialOrd 特性。

基本用法
use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
struct Struct {
    f1: u8
}

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
struct Struct {
    #[educe(PartialOrd(ignore))]
    f1: u8
}

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
enum Enum {
    V1,
    V2 {
        #[educe(PartialOrd(ignore))]
        f1: u8,
    },
    V3(
        #[educe(PartialOrd(ignore))]
        u8
    ),
}
使用另一种方法进行比较

可以通过使用 method 参数来替换字段的 PartialOrd 特性的实现,从而无需为该字段的类型实现 PartialOrd 特性。

use educe::Educe;

use std::cmp::Ordering;

fn partial_cmp(a: &u8, b: &u8) -> Option<Ordering> {
    if a > b {
        Some(Ordering::Less)
    } else if a < b {
        Some(Ordering::Greater)
    } else {
        Some(Ordering::Equal)
    }
}

trait A {
    fn value(&self) -> u8;
}

fn partial_cmp2<T: A>(a: &T, b: &T) -> Option<Ordering> {
    partial_cmp(&a.value(), &b.value())
}

#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum<T: A> {
    V1,
    V2 {
        #[educe(PartialOrd(method(partial_cmp)))]
        f1: u8,
    },
    V3(
        #[educe(PartialOrd(method(partial_cmp2)))]
        T
    ),
}
排序

每个字段都可以添加一个 #[educe(PartialOrd(rank = priority_value))] 属性,其中 priority_value 是一个整数,表示其比较优先级(值越小表示优先级越高)。字段的默认 priority_value 依赖于其序号位置(越靠近前面值越小),初始值为 isize::MIN

use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
struct Struct {
    #[educe(PartialOrd(rank = 1))]
    f1: u8,
    #[educe(PartialOrd(rank = 0))]
    f2: u8,
}

对于变体,可以显式设置判别式进行比较。

use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
#[repr(u8)]
enum Enum {
    Three { f1: u8 } = 3,
    Two(u8) = 2,
    One = 1,
}
绑定到 PartialOrd 特性或其他特性的泛型参数

如果需要,泛型参数将自动绑定到 PartialOrd 特性。

use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

use std::cmp::Ordering;

trait A {
    fn value(&self) -> u8;
}

fn partial_cmp<T: A>(a: &T, b: &T) -> Option<Ordering> {
    a.value().partial_cmp(&b.value())
}

#[derive(PartialEq, Educe)]
#[educe(PartialOrd(bound(T: std::cmp::PartialOrd, K: PartialEq + A)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(PartialOrd(method(partial_cmp)))]
        f1: K,
    },
    V3(
        T
    ),
}

在上面的情况中,T 绑定到 PartialOrd 特性,但 K 没有绑定。

您可以使用 educe 来复现 stdderive 的行为,通过使用 bound(*)。有关更多信息,请参阅 Debug 部分。

use educe::Educe;

#[derive(PartialEq, Educe)]
#[educe(PartialOrd(bound(*)))]
struct Struct<T> {
    #[educe(PartialOrd(ignore))]
    f: T,
}

Ord

使用 #[derive(Educe)]#[educe(Ord(rank = priority_value))] 来为结构体或枚举实现 Ord 特性。您也可以选择忽略特定字段或设置一个方法来替换 Ord 特性。

基本用法
use educe::Educe;

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
struct Struct {
    f1: u8
}

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
struct Struct {
    #[educe(Ord(ignore))]
    f1: u8
}

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
enum Enum {
    V1,
    V2 {
        #[educe(Ord(ignore))]
        f1: u8,
    },
    V3(
        #[educe(Ord(ignore))]
        u8
    ),
}
使用另一种方法进行比较

可以使用 method 参数来替换字段的 Ord 特性的实现,从而无需为该字段的类型实现 Ord 特性。

use educe::Educe;

use std::cmp::Ordering;

fn cmp(a: &u8, b: &u8) -> Ordering {
    if a > b {
        Ordering::Less
    } else if a < b {
        Ordering::Greater
    } else {
        Ordering::Equal
    }
}

trait A {
    fn value(&self) -> u8;
}

fn cmp2<T: A>(a: &T, b: &T) -> Ordering {
    cmp(&a.value(), &b.value())
}

#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum<T: A> {
    V1,
    V2 {
        #[educe(Ord(method(cmp)))]
        f1: u8,
    },
    V3(
        #[educe(Ord(method(cmp2)))]
        T
    ),
}
排序

每个字段都可以添加一个 #[educe(Ord(rank = priority_value))] 属性,其中 priority_value 是一个整数,表示其比较优先级(值越小表示优先级越高)。字段的默认 priority_value 依赖于其序号位置(越靠近前面值越小),初始值为 isize::MIN

use educe::Educe;

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
struct Struct {
    #[educe(Ord(rank = 1))]
    f1: u8,
    #[educe(Ord(rank = 0))]
    f2: u8,
}

对于变体,可以显式设置判别式进行比较。

use educe::Educe;

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
#[repr(u8)]
enum Enum {
    Three { f1: u8 } = 3,
    Two(u8) = 2,
    One = 1,
}
绑定到 Ord 特性或其他特性的泛型参数

如果需要,泛型参数将自动绑定到Ord特质。

use educe::Educe;

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

use std::cmp::Ordering;

trait A {
    fn value(&self) -> u8;
}

fn cmp<T: A>(a: &T, b: &T) -> Ordering {
    a.value().cmp(&b.value())
}

#[derive(PartialEq, Eq, Educe)]
#[educe(PartialOrd, Ord(bound(T: std::cmp::Ord, K: std::cmp::Ord + A)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(PartialOrd(method(cmp)))]
        f1: K,
    },
    V3(
        T
    ),
}

哈希

使用#[derive(Educe)]#[educe(Hash)]来为结构体、枚举或联合实现Hash特质。您也可以选择忽略特定字段或设置一个方法来替换Hash特质。

基本用法
use educe::Educe;

#[derive(Educe)]
#[educe(Hash)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Hash)]
enum Enum {
    V1,
    V2 {
        f1: u8,
    },
    V3(u8),
}
忽略字段

ignore 参数可以忽略特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(Hash)]
struct Struct {
    #[educe(Hash(ignore))]
    f1: u8
}

#[derive(Educe)]
#[educe(Hash)]
enum Enum {
    V1,
    V2 {
        #[educe(Hash(ignore))]
        f1: u8,
    },
    V3(
        #[educe(Hash(ignore))]
        u8
    ),
}
使用另一种哈希方法

可以使用method参数来替换字段的Hash特质实现,从而无需为该字段的类型实现Hash特质。

use educe::Educe;

use std::hash::{Hash, Hasher};

fn hash<H: Hasher>(_s: &u8, state: &mut H) {
    Hash::hash(&100, state)
}

fn hash2<H: Hasher, T>(_s: &T, state: &mut H) {
    Hash::hash(&100, state)
}

#[derive(Educe)]
#[educe(Hash)]
enum Enum<T> {
    V1,
    V2 {
        #[educe(Hash(method(hash)))]
        f1: u8,
    },
    V3(
        #[educe(Hash(method(hash2)))]
        T
    ),
}
泛型参数绑定到Hash特质或其他特质

如果需要,泛型参数将自动绑定到Hash特质。

use educe::Educe;

#[derive(Educe)]
#[educe(Hash)]
enum Enum<T, K> {
    V1,
    V2 {
        f1: K,
    },
    V3(
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

use std::hash::{Hash, Hasher};

trait A {
    fn value(&self) -> u8;
}

fn hash<H: Hasher, T: A>(s: &T, state: &mut H) {
    Hash::hash(&s.value(), state)
}

#[derive(Educe)]
#[educe(Hash(bound(T: std::hash::Hash, K: A)))]
enum Enum<T, K> {
    V1,
    V2 {
        #[educe(Hash(method(hash)))]
        f1: K,
    },
    V3(
        T
    ),
}

在上面的例子中,T被绑定到Hash特质,但K没有被绑定。

您可以使用 educe 来复现 stdderive 的行为,通过使用 bound(*)。有关更多信息,请参阅 Debug 部分。

use educe::Educe;

#[derive(Educe)]
#[educe(Hash(bound(*)))]
struct Struct<T> {
    #[educe(Hash(ignore))]
    f: T,
}
联合体

对于联合,可以使用#[educe(PartialEq(unsafe), Eq, Hash(unsafe))]属性。联合的字段不能使用其他方法进行哈希。实现是不安全的,因为它忽略了它所使用的特定字段。

use educe::Educe;

#[derive(Educe)]
#[educe(PartialEq(unsafe), Eq, Hash(unsafe))]
union Union {
    f1: u8,
    f2: i32
}

默认值

使用#[derive(Educe)]#[educe(Default)]来为结构体、枚举或联合实现Default特质。您也可以选择忽略特定字段或设置一个方法来替换Hash特质。

基本用法

对于枚举和联合,如果枚举只有一个变体或联合只有一个字段,则必须指定默认变体(对于枚举)和默认字段(对于联合)。

use educe::Educe;

#[derive(Educe)]
#[educe(Default)]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Default)]
enum Enum {
    V1,
    #[educe(Default)]
    V2 {
        f1: u8,
    },
    V3(u8),
}

#[derive(Educe)]
#[educe(Default)]
union Union {
    f1: u8,
    #[educe(Default)]
    f2: f64,
}
整个类型的默认值
use educe::Educe;

#[derive(Educe)]
#[educe(Default(expression = Struct { f1: 1 }))]
struct Struct {
    f1: u8
}

#[derive(Educe)]
#[educe(Default(expression = Enum::Struct { f1: 1 }))]
enum Enum {
    Unit,
    Struct {
        f1: u8
    },
    Tuple(u8),
}

#[derive(Educe)]
#[educe(Default(expression = Union { f1: 1 }))]
union Union {
    f1: u8,
    f2: f64,
}

您可能需要激活full特性以启用对高级表达式的支持。

特定字段的默认值
use educe::Educe;

#[derive(Educe)]
#[educe(Default)]
struct Struct {
    #[educe(Default = 1)]
    f1: u8,
    #[educe(Default = 11111111111111111111111111111)]
    f2: i128,
    #[educe(Default = 1.1)]
    f3: f64,
    #[educe(Default = true)]
    f4: bool,
    #[educe(Default = "Hi")]
    f5: &'static str,
    #[educe(Default = "Hello")]
    f6: String,
    #[educe(Default = 'M')]
    f7: char,
}

#[derive(Educe)]
#[educe(Default)]
enum Enum {
    Unit,
    #[educe(Default)]
    Tuple(
        #[educe(Default(expression = 0 + 1))]
        u8,
        #[educe(Default(expression = -11111111111111111111111111111 * -1))]
        i128,
        #[educe(Default(expression = 1.0 + 0.1))]
        f64,
        #[educe(Default(expression = !false))]
        bool,
        #[educe(Default(expression = "Hi"))]
        &'static str,
        #[educe(Default(expression = String::from("Hello")))]
        String,
        #[educe(Default(expression = 'M'))]
        char,
    ),
}

#[derive(Educe)]
#[educe(Default)]
union Union {
    f1: u8,
    f2: i128,
    f3: f64,
    f4: bool,
    #[educe(Default = "Hi")]
    f5: &'static str,
    f6: char,
}
泛型参数绑定到Default特质或其他特质

如果需要,泛型参数将自动绑定到Default特质。

use educe::Educe;

#[derive(Educe)]
#[educe(Default)]
enum Enum<T> {
    Unit,
    #[educe(Default)]
    Struct {
        f1: T
    },
    Tuple(T),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

#[derive(Educe)]
#[educe(Default(bound(T: std::default::Default)))]
enum Enum<T> {
    Unit,
    #[educe(Default)]
    Struct {
        f1: T
    },
    Tuple(T),
}
new关联函数

使用 #[educe(Default(new))] 属性,您的类型将包含一个名为 new 的附加关联函数。此函数可用于调用 default 方法。

use educe::Educe;

#[derive(Educe)]
#[educe(Default(new))]
struct Struct {
    f1: u8
}

Deref

使用 #[derive(Educe)]#[educe(Deref)] 来为结构体或枚举实现 Deref 特性。

基本用法

除非字段数量恰好为一个是不可变的,否则必须指定一个字段作为默认值以获取不可变引用。

use educe::Educe;

#[derive(Educe)]
#[educe(Deref)]
struct Struct {
    f1: u8,
    #[educe(Deref)]
    f2: u8,
}

#[derive(Educe)]
#[educe(Deref)]
enum Enum {
    Struct {
        f1: u8
    },
    Struct2 {
        f1: u8,
        #[educe(Deref)]
        f2: u8,
    },
    Tuple(u8),
    Tuple2(
        u8,
        #[educe(Deref)]
        u8
    ),
}

DerefMut

使用 #[derive(Educe)]#[educe(DerefMut)] 来为结构体或枚举实现 DerefMut 特性。

基本用法

除非字段数量恰好为一个是可变的,否则必须指定一个字段作为默认值以获取可变引用。

use educe::Educe;

#[derive(Educe)]
#[educe(Deref, DerefMut)]
struct Struct {
    f1: u8,
    #[educe(Deref, DerefMut)]
    f2: u8,
}

#[derive(Educe)]
#[educe(Deref, DerefMut)]
enum Enum {
    Struct {
        f1: u8
    },
    Struct2 {
        f1: u8,
        #[educe(Deref, DerefMut)]
        f2: u8,
    },
    Tuple(u8),
    Tuple2(
        #[educe(DerefMut)]
        u8,
        #[educe(Deref)]
        u8
    ),
}

可变引用的字段不需要与不可变引用的字段相同,但它们的类型必须一致。

Into

使用 #[derive(Educe)]#[educe(Into(type))] 来为结构体或枚举实现 Into<type> 特性。

基本用法

除非字段数量恰好为一个是 Into<type> 转换的默认值,否则需要指定一个字段。如果没有,educe 将自动尝试找到合适的字段。

use educe::Educe;

#[derive(Educe)]
#[educe(Into(u8), Into(u16))]
struct Struct {
    f1: u8,
    f2: u16,
}

#[derive(Educe)]
#[educe(Into(u8))]
enum Enum {
    V1 {
        f1: u8,
        #[educe(Into(u8))]
        f2: u8,
    },
    V2 (
        u8
    ),
}
使用另一种方法执行 Into 转换

可以使用 method 参数来替换字段的 Into 特性实现,从而无需实现该字段的类型 Into 特性。

use educe::Educe;

fn into(v: u16) -> u8 {
    v as u8
}

#[derive(Educe)]
#[educe(Into(u8))]
enum Enum {
    V1 {
        #[educe(Into(u8, method(into)))]
        f1: u16,
    },
    V2 (
        u8
    ),
}
将泛型参数绑定到 Into 特性或其他特性

如果需要,通用参数将自动绑定到 Into<type> 特性。

use educe::Educe;

#[derive(Educe)]
#[educe(Into(u8))]
enum Enum<T, K> {
    V1 {
        f1: K,
    },
    V2 (
        T
    ),
}

或者,您可以自己设置 where 断言。

use educe::Educe;

fn into<T>(_v: T) -> u8 {
    0
}

#[derive(Educe)]
#[educe(Into(u8, bound(K: Into<u8>)))]
enum Enum<T, K> {
    V1 {
        f1: K,
    },
    V2 (
        #[educe(Into(u8, method(into)))]
        T
    ),
}

Crates.io

https://crates.io/crates/educe

文档

https://docs.rs/educe

许可证

MIT

依赖

~285–740KB
~17K SLoC