#default-value #default #derive #named-fields

无std better_default

std Default derive,但允许自定义默认字段值并有一些升级。

6个稳定版本

1.0.5 2024年6月27日
1.0.3 2024年6月26日
1.0.2 2024年6月25日
1.0.0 2024年6月15日

过程宏中排名201

每月下载量42

Apache-2.0

46KB
413

更好的默认值

具有更多自定义功能和一些升级的std Default derive。

Static Badge Crates.io Version docs.rs Crates.io License

此crate提供了一个名为Default的单个derive特型。此derive特型充当std Default derive特型,但允许修改每个字段的默认值。它还允许将具有字段的枚举变体标记为默认值。

功能

  • 执行std Default derive特型所做的所有事情
  • 支持将具有字段的枚举变体标记为默认值
  • 支持覆盖每个字段的默认值
  • 支持无std,这意味着它将输出无std的代码。**注意,该库本身需要std库**。

请参阅Examples章节中的所有这些功能。

如何使用

在此处做任何事情之前,如果您想覆盖枚举变体的字段,请**首先将其标记为默认值**

use better_default::Default;

#[derive(Default)]
enum Enum {
    #[default]
    Variant {
        ...
    },
    ...
}

1. 覆盖默认值

有两种覆盖默认值的方法:使用逐字段属性或顶层默认属性。

逐字段属性

逐字段属性只是您放在要覆盖默认值的字段之上的属性。

语法如下

#[default( <expression> )]
<field_ident>: <field_type>

您可以在expression块中放置任何您想要的内容,只要它可以通过syn::Expr正确解析即可。

以下是一个此方法实施的示例

use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    #[default] // mark the variant as default (this is mandatory)
    Variant1 {
        #[default(1)] // set the default value of `first` to 1
        first: u32,

        // keep the default value for `second`
        second: String,
    },

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1 { first: 1, second: "" }"
    println!("{:?}", default);
}

顶层默认属性

您不需要在结构体/枚举变体的所有字段上放置属性,只需在顶部放置一个属性,其中包含所有默认值覆盖。

顶层属性的语法如下

use better_default::Default;

#[derive(Default)]
#[default((<field_id>: <expression>),*)]
struct Struct { 
    ...
} // the struct can have unnamed fields

#[derive(Default)]
enum Enum {
    #[default((<field_id>: <expression>),*)]
    Variant { ... } // the variant can have unnamed fields
}

field_id在这里可以表示两种含义:如果您处理命名字段,则应在此处放置字段标识符。如果您处理未命名字段,则**您应放置字段的顺序**(第一个为0,第二个为1,依此类推)。

再次强调,您可以在 expression 块中放入您想要的任何内容,只要它能被 syn::Expr 正确解析。

以下是两个示例,一个涵盖未命名字段,另一个涵盖已命名字段。

use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    // mark the variant as default, and also specifies the default values :
    //      - the default value of the first field (which is at index 0) is set to 2
    //      - the second field (which is at index 1) will have it's default value set to "Hello world!"
    #[default(0: 2, 1: "Hello world!".to_string())]
    Variant1(u32, String),

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1(2, "Hello world!")"
    println!("{:?}", default);
}
use better_default::Default;

#[derive(Default, Debug)]
#[default(field1: 1, field2: "Hello world!".to_string())]
struct Struct {
    field1: u32, 
    field2: String
}

fn main() {
    let default = Struct::default();
    println!("{:?}", default) // should print "Struct { field1: 1, field2: "Hello world!" }"
}

最后一点:这两种方法可以结合使用,这意味着您可以有一个包含一些默认值的顶层属性,同时某些字段有自己的属性。

示例

  1. 按字段方式:使用按字段属性

按字段属性更适合具有命名字段的 struct / enum 变体。

use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    #[default] // mark the variant as default (this is mandatory)
    Variant1 {
        #[default(1)] // set the default value of `first` to 1
        first: u32,

        // keep the default value for `second`
        second: String,
    },

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1 { first: 1, second: "" }"
    println!("{:?}", default);
}
use better_default::Default;

#[derive(Default, Debug)]
// Structs don't need to be mark as default with a top attribute. They're optional.
struct Struct {
    #[default(10)] // set the default value of field1 to be 10
    field1: u32,

    // keeps the usual default value for field2
    field2: String,
}

fn main() {
    let default = Struct::default();
    println!("{:?}", default) // should print "Struct { field1: 10, field2: "" }"
}

虽然不推荐,但您也可以在未命名字段上使用它们。

use better_default::Default;

#[derive(Default, Debug)]
// Structs don't need to be mark as default with a top attribute. They're optional.
struct Struct (
    #[default(10)] // set the default value of field1 to be 10
    u32,

    // keeps the usual default value for field2
    String,
);

fn main() {
    let default = Struct::default();
    println!("{:?}", default) // should print "Struct(10, "")"
}
use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    #[default] // mark the variant as default (this is mandatory)
    Variant1 (
        #[default(1)] // set the default value to 1
        u32,

        // keep the default value
        String,
    ),

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1(1, "")"
    println!("{:?}", default);
}
  1. 一次性方式:使用顶层默认属性

顶层属性的特别之处在于您可以在同一个地方定义所有默认值。

这里不需要表示所有字段,只需要您想修改的字段。

use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    // mark the variant as default, and also specifies the default values :
    //      - the first field keeps it's usual default value.
    //      - the second field (which is at index 1) will have it's default value set to "Hello world!"
    #[default(1: "Hello world!".to_string())]
    Variant1(u32, String),

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1(0, "Hello world!")"
    println!("{:?}", default);
}
use better_default::Default;

#[derive(Default, Debug)]
// here we can use the top default attribute to customize the default values of our fields.
//      - we change the default value of the first field (represented by the index 0) to 1
#[default(0: 1, 1: "a".to_string())]
struct Struct(u32, String);

fn main() {
    let default = Struct::default();
    println!("{:?}", default) // should print "Struct(1, "a")"
}

这也可以用于命名字段

use better_default::Default;

#[derive(Default, Debug)]
enum Enum {
    // mark the variant as default, and also specifies the default values :
    //      - the first field keeps it's usual default value.
    //      - the second field (field2) will have it's default value set to "Hello world!"
    #[default(field2: "Hello world!".to_string())]
    Variant1 {
        field1: u32, 
        field2: String
    },

    Variant2,

    Variant3,
}

fn main() {
    let default = Enum::default();
    
    // should print "Variant1 { 0, "Hello world!" }"
    println!("{:?}", default);
}
use better_default::Default;

#[derive(Default, Debug)]
#[default(field1: 1, field2: "Hello world!".to_string())]
struct Struct {
    field1: u32, 
    field2: String
}

fn main() {
    let default = Struct::default();
    println!("{:?}", default) // should print "Struct { field1: 1, field2: "Hello world!" }"
}

贡献

您可以通过创建 pull request 来为项目做出贡献。

以下是我在这个库中使用的工具

  • rustdoc-include,它允许我直接将说明文导入到 lib.rs 而无需复制。这就是为什么您可以在 lib.rs 中看到那些 // #[include_doc(...)]。使用 scripts 文件夹中的 build_crate_doc 脚本来更新它们。

许可证

Apache 2.0 许可证。

依赖关系

~315–780KB
~19K SLoC