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 日 |
#63 在 Rust 模式
735,383 每月下载量
用于 674 个软件包 (106 个直接)
410KB
8K SLoC
Educe
该软件包提供了旨在简化 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 可以复制 std 的 derive 的行为,为每个泛型参数生成一个绑定,而不考虑它在结构体中的使用方式。
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 来复制 std 的 derive 的行为,通过使用 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
),
}
请注意,对于实现了 Copy 和 Clone 特性的类型,使用自定义克隆方法可能并不完全合适。
联合体
#[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 来复现 std 的 derive 的行为,通过使用 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 来复现 std 的 derive 的行为,通过使用 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 来复现 std 的 derive 的行为,通过使用 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
文档
许可证
依赖
~285–740KB
~17K SLoC