如何仅将某些结构成员设置为其默认值?

me'*_*me' 11 struct default rust

我有结构B

struct A {}

struct B {
    a: A,
    b: u32,
    c: i8,
    z: usize,
}
Run Code Online (Sandbox Code Playgroud)

A没有Default实现,也没有有意义的默认值。所有字段bz需要初始化为默认值(在本例中为 0),并将A初始化为某个运行时值:

let b = B {
    a: some_a(),
    b: 0,
    c: 0,
    z: 0,
};
Run Code Online (Sandbox Code Playgroud)

这并不理想。

更糟糕的是,如果aa要将 an 添加到结构中,则需要将另一个成员添加到初始化程序中。使用..Default::default()不起作用,因为B没有Default实现,因为A默认值中的任何 s 计算成本都太高,无法在事后简单地丢弃。此外,无论如何,我在实现中都需要一个非常长的结构初始化程序Default

有没有什么方法可以将剩余的结构成员设置为其默认值(以便将其b设置为默认值u32)而不写出所有成员名称?

优选地,当添加新成员时,结构初始值设定项所需的更改应该最小。这意味着这并不理想:

let b = B {
    a: some_a(),
    b: Default::default(),
    c: Default::default(),
    z: Default::default(),
};
Run Code Online (Sandbox Code Playgroud)

Pet*_*all 8

如果您有大型结构,则可以通过派生构建器或构造函数来使您的生活更轻松。有一些板条箱可以做到这一点,其中一个流行的是derive_builder.

使用该板条箱,您可以执行以下操作:

use derive_builder::Builder;

// this derive will generate a struct called BBuilder
#[derive(Builder)]
struct B {
    a: A,
    #[builder(default = "0")]
    b: u32,
    #[builder(default = "0")]
    c: i8,
    /* ... */
    #[default(default = "0")]
    z: usize
}


fn main() {
    let a = A { ... };

    // all default values for fields b..z
    let b = BBuilder::default().a(a).build().unwrap();

    // or specify just some of the fields
    let b = BBuilder::default()
        .a(a)
        .c(42)
        .z(255)
        .build()
        .unwrap();
}
Run Code Online (Sandbox Code Playgroud)

只要字段具有默认值,添加新字段B就不会影响使用 的代码。BBuilder缺点是,如果您错过了必填字段,则会出现运行时恐慌,而不是编译错误。


另一个箱子是derive-new,它更简单一些。你可以像这样使用它:

use derive_new::new;

#[derive(new)]
struct B {
    a: A,
    #[new(default)] 
    b: u32,
    #[new(default)] 
    c: i8,
    /* ... */
    #[new(default)]
    z: usize
}

fn main() {
    let a = A { ... };

    // all default values for fields b..z
    let b = B::new(a);

    // To specify some of the default fields, you need to mutate
    let mut b = B::new(a);
    b.c = 42;
    b.z = 255;
}
Run Code Online (Sandbox Code Playgroud)

这不会生成任何额外的结构,它只是添加一个new方法,该方法接受所有非默认参数。如果您遗漏了任何非默认字段,则会出现编译错误。