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