Rust编程语言内置的derive
特点能够快速地替咱们的类型加上内置的特性,不过会要求该类型内的字段也都要先实作相同的特性,而且许多时分运用derive
特点实作出来的特性并不能达到咱们期望的功用。
比如说以下这个用来作为唯读数据库的数据模型的结构体:
#[derive(Hash, PartialEq, Eq)]
pub struct Person {
uid: u64,
name: String,
age: u8
}
仿制代码
咱们希望这个Person
结构体能够被哈希,且用有判别两个Person
结构体是否相同的功用。以上的实作办法虽然在运用起来并没有什么太大的问题,但是功能不会很好,因为经过derive特点实作的Hash
特性,会去计算一切字段的哈希值,但是在这里咱们其实只要去计算uid
这个字段的哈希值就能够了。同理,PartialEq
特性也是相同只需求去判别uid
这个字段是否PartialEq
就好了,真实不需求用上一切字段。
再来,假如咱们加了某个没有一起实作Hash
、PartialEq
和Eq
特性的字段,这个Person
结构体就没有办法被编译了。
例如:
#[derive(Hash, PartialEq, Eq)]
pub struct Person {
uid: u64,
name: String,
age: u8,
score: f64,
}
仿制代码
以上程序,因为类型为f64
的score
字段没有实作Hash
和Eq
特性,所以会编译失败。
还有,假如咱们的类型字段有用到泛型的话,泛型类型参数也必需求加上特性的约束,不然也会无法编译。
例如:
#[derive(Hash, PartialEq, Eq)]
pub struct Person<T> {
uid: u64,
name: T,
age: u8,
}
仿制代码
若以上这个Person
结构体要成功运用derive特点来实作Hash
、PartialEq
和Eq
特性的话,要改成以下这样:
use std::hash::Hash;
#[derive(Hash, PartialEq, Eq)]
pub struct Person<T: Hash + PartialEq + Eq> {
uid: u64,
name: T,
age: u8,
}
仿制代码
但是做这样的修正或许会使这个结构体想要体现的功用和本来的不同。本来咱们或许预期泛型类型参数T
便是一个恣意的类型,纷歧定要实作Hash
、PartialEq
和Eq
特性,但是将其加上特性的约束之后,T
就不能是恣意的类型了。为了处理这个问题,咱们必需求手动实作特性,而且只在实作时替泛型类型参数加上特性的约束,而不是像以上这样直接在类型上进行约束。
Educe
「Educe」是笔者开发的进程式宏套件,能够用来加强原先Rust编程语言用derive
特点来实作内置特性的办法,使得这类程序序宏能够在更多常见的场景下直接运用,让开发者不需求手动去写impl
相关的程序。
Crates.io
crates.io/crates/educ…
Cargo.toml
educe = “0.4.20”
运用办法
Educe现在能够实作的特性有Debug
、PartialEq
、Eq
、PartialOrd
、Ord
、Hash
、Default
、Clone
、Copy
、Deref
、DerefMut
。
上面的泛型类型参数例子能够很轻易地用Educe来改写,程序如下:
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Hash(bound), PartialEq(bound), Eq(bound))]
pub struct Person<T> {
uid: u64,
name: T,
age: u8,
}
仿制代码
特征
在缺省的景象下,Educe会激活一切有支撑的特性。假如想要禁用它们的话,在Cargo.toml
设置档中,能够不激活缺省特性,只把自己想要用的特性加入features
中来激活就好。
如下:
[dependencies.educe]
version = "*"
features = ["Debug", "Default", "Hash", "Clone", "Copy"]
default-features = false
仿制代码
Debug
在类型上加上#[derive(Educe)]
和#[educe(Debug)]
特点,就能够替该类型实作Debug
特性。类型可所以恣意结构体、恣意枚举和恣意联合(union)。此外,它还有支撑类型称号、变体称号和字段称号的改动,也能够疏忽掉指定的字段,还能够替指定的字段设置格局化时要运用的办法和(或)特性。更方便的是,它还能够把一般结构体当作元组结构体(tuple struct)来格局化,或是反过来把元组结构体当作一般结构体来格局化。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Debug)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Debug)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
改动类型称号、变体称号或是字段称号
name
特点能够用来重命名一个类型、变体或是字段。
#[macro_use]
extern crate 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
特点能够用来疏忽指定的字段。
#[macro_use]
extern crate 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
特点能够用来设置类型或是变体下的字段是否要具有称号。
#[macro_use]
extern crate 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
),
}
仿制代码
运用别的的办法或特性来做格局化
trait
和method
参数能够被用在字段上,替代该字段的Debug
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为fmt
。
#[macro_use]
extern crate educe;
use std::fmt::{self, Formatter};
fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
trait A {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Debug)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Debug(method = "fmt"))]
f1: u8,
},
V3(
#[educe(Debug(trait = "std::fmt::UpperHex"))]
u8,
#[educe(Debug(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上Debug
特性约束,或是手动设置其它约束
在类型上加上#[educe(Debug(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Debug
特性的条件下来替类型实作Debug
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Debug(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
use std::fmt::{self, Formatter};
fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
trait A {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Debug(bound = "T: std::fmt::Debug, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Debug(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
联合
联合并不会依照其字段的类型来做格局化,而是会将联合在内存中的值以u8
切片的办法来格局化,因为咱们无法在程序运行阶段知道当前的联合究竟是在用哪个字段。联合中的字段无法被省掉、重命名或是用其它的特性或是办法来格局化。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Debug)]
struct Union {
f1: u8,
f2: i32,
}
仿制代码
PartialEq
在类型上加上#[derive(Educe)]
和#[educe(PartialEq)]
特点,就能够替该类型实作PartialEq
特性。类型可所以恣意结构体和恣意枚举。此外,它还能够疏忽掉指定的字段,也能够替指定的字段设置在比较是否相一起要运用的办法和(或)特性。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
疏忽字段
ignore
特点能够用来疏忽指定的字段。
#[macro_use]
extern crate 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
),
}
仿制代码
运用别的的办法或特性来做比较
trait
和method
参数能够被用在字段上,替代该字段的PartialEq
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为eq
。
#[macro_use]
extern crate educe;
fn eq(a: &u8, b: &u8) -> bool {
a + 1 == *b
}
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq)]
enum Enum<T: A> {
V1,
V2 {
#[educe(PartialEq(method = "eq"))]
f1: u8,
},
V3(
#[educe(PartialEq(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上PartialEq
特性约束,或是手动设置其它约束
在类型上加上#[educe(PartialEq(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作PartialEq
特性的条件下来替类型实作PartialEq
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialEq(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
Eq
在类型上加上#[derive(Educe)]
和#[educe(Eq)]
特点,就能够替该类型实作Eq
特性。类型可所以恣意结构体、恣意枚举和恣意联合(union)。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
泛型参数主动加上Eq
特性约束,或是手动设置其它约束
在类型上加上#[educe(Eq(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Eq
特性的条件下来替类型实作Eq
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"), Eq(bound = "T: std::cmp::PartialEq, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialEq(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
Eq
特性相依于PartialEq
(PartialEq<Self>
)特性,在手动约束泛型类型参数要实作的特性之前要注意一下。
PartialOrd
在类型上加上#[derive(Educe)]
和#[educe(PartialOrd)]
特点,就能够替该类型实作PartialOrd
特性。类型可所以恣意结构体和恣意枚举。此外,它还能够疏忽掉指定的字段,也能够替指定的字段设置在比较是否相一起要运用的办法和(或)特性。别的,变体和字段也都能够自订摆放次序。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
疏忽字段
ignore
特点能够用来疏忽指定的字段。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
#[educe(PartialOrd(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
V1,
V2 {
#[educe(PartialOrd(ignore))]
f1: u8,
},
V3(
#[educe(PartialOrd(ignore))]
u8
),
}
仿制代码
运用别的的办法或特性来做比较
trait
和method
参数能够被用在字段上,替代该字段的PartialOrd
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为partial_cmp
。
#[macro_use]
extern crate 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 partial_cmp(&self, b: &Self) -> Option<Ordering>;
}
impl A for i32 {
fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
if self > b {
Some(Ordering::Less)
} else if self < b {
Some(Ordering::Greater)
} else {
Some(Ordering::Equal)
}
}
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum<T: std::cmp::PartialEq + A> {
V1,
V2 {
#[educe(PartialOrd(method = "partial_cmp"))]
f1: u8,
},
V3(
#[educe(PartialOrd(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上PartialOrd
特性约束,或是手动设置其它约束
在类型上加上#[educe(PartialOrd(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作PartialOrd
特性的条件下来替类型实作PartialOrd
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), PartialOrd(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
use std::cmp::Ordering;
trait A {
fn partial_cmp(&self, b: &Self) -> Option<Ordering>;
}
impl A for i32 {
fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
if self > b {
Some(Ordering::Less)
} else if self < b {
Some(Ordering::Greater)
} else {
Some(Ordering::Equal)
}
}
}
#[derive(Educe)]
#[educe(PartialEq(bound), PartialOrd(bound = "T: std::cmp::PartialOrd, K: std::cmp::PartialOrd + A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialOrd(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
摆放次序
每个字段都能够加上#[educe(PartialOrd(rank = priority_value))]
特点,其间的priority_value
是一个正整数,用来决议比较的优先级(priority_value
愈小就愈优先)。字段的priority_value
默认值与其被界说的序数(也便是第几个字段)有关,而且总是会小于自订的priority_value
值。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
#[educe(PartialOrd(rank = 1))]
f1: u8,
#[educe(PartialOrd(rank = 0))]
f2: u8,
}
仿制代码
每个变体都能够加上#[educe(PartialOrd(rank = comparison_value))]
特点,其间的comparison_value
是一个正整数,用来覆写变体代表的值或是序数的值,用于比较大小时。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
#[educe(PartialOrd(rank = 2))]
Two,
#[educe(PartialOrd(rank = 1))]
One,
}
仿制代码
Ord
在类型上加上#[derive(Educe)]
和#[educe(Ord)]
特点,就能够替该类型实作Ord
特性。类型可所以恣意结构体和恣意枚举。此外,它还能够疏忽掉指定的字段,也能够替指定的字段设置在比较是否相一起要运用的办法和(或)特性。别的,变体和字段也都能够自订摆放次序。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
疏忽字段
ignore
特点能够用来疏忽指定的字段。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
#[educe(Ord(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
V1,
V2 {
#[educe(Ord(ignore))]
f1: u8,
},
V3(
#[educe(Ord(ignore))]
u8
),
}
仿制代码
运用别的的办法或特性来做比较
trait
和method
参数能够被用在字段上,替代该字段的Ord
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为cmp
。
#[macro_use]
extern crate 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 cmp(&self, b: &Self) -> Ordering;
}
impl A for i32 {
fn cmp(&self, b: &i32) -> Ordering {
if self > b {
Ordering::Less
} else if self < b {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum<T: std::cmp::PartialOrd + A> {
V1,
V2 {
#[educe(Ord(method = "cmp"))]
f1: u8,
},
V3(
#[educe(Ord(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上Ord
特性约束,或是手动设置其它约束
在类型上加上#[educe(Ord(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Ord
特性的条件下来替类型实作Ord
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
use std::cmp::Ordering;
trait A {
fn cmp(&self, b: &Self) -> Ordering;
}
impl A for i32 {
fn cmp(&self, b: &i32) -> Ordering {
if self > b {
Ordering::Less
} else if self < b {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound = "T: std::cmp::Ord, K: std::cmp::Ord + A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Ord(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
摆放次序
每个字段都能够加上#[educe(Ord(rank = priority_value))]
特点,其间的priority_value
是一个正整数,用来决议比较的优先级(priority_value
愈小就愈优先)。字段的priority_value
默认值与其被界说的序数(也便是第几个字段)有关,而且总是会小于自订的priority_value
值。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
#[educe(Ord(rank = 1))]
f1: u8,
#[educe(Ord(rank = 0))]
f2: u8,
}
仿制代码
每个变体都能够加上#[educe(Ord(rank = comparison_value))]
特点,其间的comparison_value
是一个正整数,用来覆写变体代表的值或是序数的值,用于比较大小时。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
#[educe(Ord(rank = 2))]
Two,
#[educe(Ord(rank = 1))]
One,
}
仿制代码
Hash
在类型上加上#[derive(Educe)]
和#[educe(Hash)]
特点,就能够替该类型实作Hash
特性。类型可所以恣意结构体和恣意枚举。此外,它还能够疏忽掉指定的字段,也能够替指定的字段设置哈希时要运用的办法和(或)特性。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Hash)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Hash)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
疏忽字段
ignore
特点能够用来疏忽指定的字段。
#[macro_use]
extern crate 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
),
}
仿制代码
运用别的的办法或特性来做哈希
trait
和method
参数能够被用在字段上,替代该字段的Hash
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为hash
。
#[macro_use]
extern crate educe;
use std::hash::{Hash, Hasher};
fn hash<H: Hasher>(_s: &u8, state: &mut H) {
Hash::hash(&100, state)
}
trait A {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&100, state)
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Hash)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Hash(method = "hash"))]
f1: u8,
},
V3(
#[educe(Hash(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上Hash
特性约束,或是手动设置其它约束
在类型上加上#[educe(Hash(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Hash
特性的条件下来替类型实作Hash
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Hash(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
use std::hash::{Hash, Hasher};
fn hash<H: Hasher>(_s: &u8, state: &mut H) {
Hash::hash(&100, state)
}
trait A {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&100, state)
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Hash(bound = "T: std::hash::Hash, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Hash(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
Default
在类型上加上#[derive(Educe)]
和#[educe(Default)]
特点,就能够替该类型实作Default
特性。类型可所以恣意结构体、恣意枚举和恣意联合。此外,它还能直接指定整个类型的默认值,或是类型内特定字段的默认值。
根本用法
对于枚举和联合,您必需求再指使一个枚举的变体或是一个联合的字段来当作默认值,除非该枚举的变体数量或是联合的字段数量刚好只要一个。
#[macro_use]
extern crate 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,
}
仿制代码
整个类型的默认值
替类型加上#[educe(Default(expression = "expression"))]
特点,能够用一个表达式来当作是这个类型的默认值。
#[macro_use]
extern crate 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,
}
仿制代码
指定字段的默认值
也能够替字段加上#[educe(Default = literal)]
或#[educe(Default(expression = "expression"))]
特点,能够直接指使一个定数值或是一个表达式作为该字段的默认值。
#[macro_use]
extern crate 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
特性约束,或是手动设置其它约束
在类型上加上#[educe(Default(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Default
特性的条件下来替类型实作Default
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Default(bound))]
enum Enum<T> {
Unit,
#[educe(Default)]
Struct {
f1: T
},
Tuple(T),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate 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
相关函数。这个new
相关函数会去调用Default
特性的default
相关函数。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Default(new))]
struct Struct {
f1: u8
}
仿制代码
Clone
在类型上加上#[derive(Educe)]
和#[educe(Clone)]
特点,就能够替该类型实作Clone
特性。类型可所以恣意结构体、恣意枚举和恣意联合。此外,它还能够替指定的字段设置在复制时要运用的办法和(或)特性。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Clone)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Clone)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
运用别的的办法或特性来做复制
trait
和method
参数能够被用在字段上,替代该字段的Clone
特性需求。假如您只要设置trait
的参数的话,method
参数会被主动缺省为clone
。
#[macro_use]
extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Clone)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Clone(method = "clone"))]
f1: u8,
},
V3(
#[educe(Clone(trait = "A"))]
T
),
}
仿制代码
泛型参数主动加上Clone
特性约束,或是手动设置其它约束
在类型上加上#[educe(Clone(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Clone
特性或是Copy
特性的条件下(后者会发生在有运用#[educe(Copy)]
特点时)来替类型实作Clone
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Clone(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Clone(bound = "T: std::clone::Clone, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Clone(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
联合
#[educe(Clone)]
特点能够被用在联合上,但是有个前提,便是这个联合必需求实作Copy
特性。联合中的字段无法用其它的特性或是办法来复制。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Copy, Clone)]
union Union {
f1: u8,
}
仿制代码
Copy
在类型上加上#[derive(Educe)]
和#[educe(Copy)]
特点,就能够替该类型实作Copy
特性。类型可所以恣意结构体、恣意枚举和恣意联合。
根本用法
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Copy, Clone)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Copy, Clone)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
仿制代码
泛型参数主动加上Copy
特性约束,或是手动设置其它约束
在类型上加上#[educe(Copy(bound))]
特点,会在该类型用到的泛型类型参数有被约束为有必要实作Copy
特性的条件下来替类型实作Copy
特性。
#[macro_use]
extern crate educe;
#[derive(Educe)]
#[educe(Copy(bound), Clone(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
仿制代码
或许,您也能够自行编撰where
语法后的约束条件,如下:
#[macro_use]
extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Copy(bound = "T: Copy, K: A + Copy"), Clone(bound = "T: Copy, K: A + Copy"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Clone(trait = "A"))]
f1: K,
},
V3(
T
),
}
仿制代码
Copy
和Clone
假如您用Educe来一起实作Copy
和Clone
特性,且并没有手动指定字段要用来做复制的办法或是特性的话,则Clone
特性的约束条件(bound)中有必要有Copy
特性,这是为了要完成Copy, Clone
的功能优化。
Deref
在类型上加上#[derive(Educe)]
和#[educe(Deref)]
特点,就能够替该类型实作Deref
特性。类型可所以恣意结构体和恣意枚举。
根本用法
您需求指定一个字段作为缺省获得的不可变参阅的字段,除非该结构体或是枚举的变体的字段数量刚好只要一个。
#[macro_use]
extern crate 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
特性。类型可所以恣意结构体和恣意枚举。
根本用法
您需求指定一个字段作为缺省获得的可变参阅的字段,除非该结构体或是枚举的变体的字段数量刚好只要一个。
#[macro_use]
extern crate 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
),
}
仿制代码
不可变参阅字段和可变参阅字段纷歧定要相同,但是它们的类型必需求是相同的。
原文转自:magiclen.org/educe/
关于作者 Magic Len
Magic Len,台湾台中大肚山上人,结业于台中高工信息科和台湾科技大学信息工程系,曾在桃机航警局服役。酷爱自然也酷爱科学,喜欢和别人共享自己的知识与经历。假如有爱好知道作者,能够加Facebook(点我),而且请注明是从MagicLen来的。