#default #variant #enums #default-value

default_variant

用于指定在派生 Default 时使用的变体或值的进程宏

1 个不稳定版本

0.1.0 2022年12月30日

#1815 in 过程宏

MIT/Apache

19KB
113

默认变体

过程属性宏,用于指定枚举的默认值。给定 default 属性的参数,会推导出相应的 Default 实现。

使用 #[default(...)],枚举的默认实现不再需要常见的样板代码,通常只是一个简单的(通常是平凡的)表达式。

示例

单元变体

最简单的用法是单元变体(即无字段的变体),其中将变体的名称作为参数传递给 default 属性。

use default_variant::default;

#[derive(PartialEq, Debug)]
#[default(Zero)]
//        ^^^^ expands to `Self::Zero`
pub enum Nat {
    Zero,
    Succ(Box<Self>)
}

assert_eq!(Nat::default(), Nat::Zero);

关联常量

提供标识符不会限制默认值必须是变体。如果已定义关联常量(当然,与枚举具有相同的类型),则该常量也可以作为有效输入。

假设我们有一个 Expr 类型(由一些标识符类型 Id 参数化),用于模拟AST中的表达式,我们希望将 () 的表示用作我们的默认表达式,其中我们将 () 表示为空的 Expr::Tuple 变体。

use default_variant::default;

#[default(UNIT)]
//        ^^^^ expands to `Self::UNIT`
pub enum Expr<Id> {
    Var(Id),
    Tuple(Vec<Self>),
    /* other variants */
}

impl<Id> Expr<Id> {
    pub const UNIT: Self = Self::Tuple(vec![]);
    /* other fun but totally irrelevant stuff  */
}

// We'll (arbitrarily) parametrize `Expr` by `&'static str`
// here since the compiler can't infer `Id` strictly from
// this context due to its lack of appearance, as well as
// use the `matches` macro to pattern match for equality
// since we won't make assumptions about `Id` for this
// simple example
matches!(Expr::default(), Expr::Tuple(elems) if elems.is_empty())

元组变体

元组变体可以使用与不使用枚举名称限定符形成表达式相同的方式使用。

请注意,传入的值具有与 Default::default() 方法中的 impl-块体相同的范围。

use default_variant::default;

#[default(Coord(0, 0))]
//        ^^^^^^^^^^^ expands to `Self::Coord`
enum Position {
    Coord(usize, usize),
    /* some other variants */
}

assert_eq!(Position::default(), Position::Coord(0, 0));

关联方法

元组变体不是 default 接受的唯一“可调用”表达式。任何在给定枚举的 impl-块中定义的关联方法(虽然可以接受参数,但不能接收接收器)也是有效输入。

use default_variant::default;

#[default(my_method())]
//        ^^^^^^^^^^^ expands to `Self::my_method()`
enum MyEnum {
    /* some variants */
}

impl MyEnum {
    fn my_method() -> Self {
        /* some logic */
    }
}

结构变体

要使用结构体变体作为默认值,只需传递相关的结构体变体(不包括枚举作为限定符)。

use default_variant::default;

#[derive(PartialEq, Debug)]
#[default(Foo { one: 1, two: 2 })]
//        ^^^ expands to `Self::Foo { one: 1, two: 2 }
pub enum FooBarBaz {
    Foo { one: u8, two: u8 },
    Bar(bool),
    Baz(char)
}

assert_eq!(FooBarBaz::default(), FooBarBaz::Foo { one: 1, two: 2 });

where子句

我们还可以在default的参数中包含where子句。这些谓词允许在不需要在枚举定义中添加界限的情况下,通用地使用默认方法。传递给defaultwhere子句随后会迅速添加到派生的Default实现中的where子句。

use default_variant::default;

#[default(
    Two(Default::default(), Default::default())
    where
        A: Default,
        B: Default
)]
#[derive(Debug, PartialEq)]
pub enum Pairs<A, B> {
    Two(A, B),
    /* other variants */
}

// we'll arbitrarily parametrize `Pairs` with primitives
// that have known defaults for demonstrative purposes
assert_eq!(Pairs::<bool, usize>::default(), Pairs::Two(false, 0));

依赖项

~1.5MB
~36K SLoC