Rust编程语言内置的derive特点能够快速地替咱们的类型加上内置的特性,不过会要求该类型内的字段也都要先实作相同的特性,而且许多时分运用derive特点实作出来的特性并不能达到咱们期望的功用。

比如说以下这个用来作为唯读数据库的数据模型的结构体:

#[derive(Hash, PartialEq, Eq)]
pub struct Person {
    uid: u64,
    name: String,
    age: u8
}
仿制代码

咱们希望这个Person结构体能够被哈希,且用有判别两个Person结构体是否相同的功用。以上的实作办法虽然在运用起来并没有什么太大的问题,但是功能不会很好,因为经过derive特点实作的Hash特性,会去计算一切字段的哈希值,但是在这里咱们其实只要去计算uid这个字段的哈希值就能够了。同理,PartialEq特性也是相同只需求去判别uid这个字段是否PartialEq就好了,真实不需求用上一切字段。

再来,假如咱们加了某个没有一起实作HashPartialEqEq特性的字段,这个Person结构体就没有办法被编译了。

例如:

#[derive(Hash, PartialEq, Eq)]
pub struct Person {
    uid: u64,
    name: String,
    age: u8,
    score: f64,
}
仿制代码

以上程序,因为类型为f64score字段没有实作HashEq特性,所以会编译失败。

还有,假如咱们的类型字段有用到泛型的话,泛型类型参数也必需求加上特性的约束,不然也会无法编译。

例如:

#[derive(Hash, PartialEq, Eq)]
pub struct Person<T> {
    uid: u64,
    name: T,
    age: u8,
}
仿制代码

若以上这个Person结构体要成功运用derive特点来实作HashPartialEqEq特性的话,要改成以下这样:

use std::hash::Hash;
#[derive(Hash, PartialEq, Eq)]
pub struct Person<T: Hash + PartialEq + Eq> {
    uid: u64,
    name: T,
    age: u8,
}
仿制代码

但是做这样的修正或许会使这个结构体想要体现的功用和本来的不同。本来咱们或许预期泛型类型参数T便是一个恣意的类型,纷歧定要实作HashPartialEqEq特性,但是将其加上特性的约束之后,T就不能是恣意的类型了。为了处理这个问题,咱们必需求手动实作特性,而且只在实作时替泛型类型参数加上特性的约束,而不是像以上这样直接在类型上进行约束。

Educe

「Educe」是笔者开发的进程式宏套件,能够用来加强原先Rust编程语言用derive特点来实作内置特性的办法,使得这类程序序宏能够在更多常见的场景下直接运用,让开发者不需求手动去写impl相关的程序。

Crates.io

crates.io/crates/educ…

Cargo.toml

educe = “0.4.20”

运用办法

Educe现在能够实作的特性有DebugPartialEqEqPartialOrdOrdHashDefaultCloneCopyDerefDerefMut

上面的泛型类型参数例子能够很轻易地用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
    ),
}
仿制代码
运用别的的办法或特性来做格局化

traitmethod参数能够被用在字段上,替代该字段的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
    ),
}
仿制代码
运用别的的办法或特性来做比较

traitmethod参数能够被用在字段上,替代该字段的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
    ),
}
仿制代码
运用别的的办法或特性来做比较

traitmethod参数能够被用在字段上,替代该字段的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
    ),
}
仿制代码
运用别的的办法或特性来做比较

traitmethod参数能够被用在字段上,替代该字段的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
    ),
}
仿制代码
运用别的的办法或特性来做哈希

traitmethod参数能够被用在字段上,替代该字段的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),
}
仿制代码
运用别的的办法或特性来做复制

traitmethod参数能够被用在字段上,替代该字段的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
    ),
}
仿制代码
CopyClone

假如您用Educe来一起实作CopyClone特性,且并没有手动指定字段要用来做复制的办法或是特性的话,则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来的。