#builder #field #default #struct #generate #methods #self

default-struct-builder

为结构体每个字段生成构建器方法

8个版本 (4个重大更新)

0.5.0 2023年8月4日
0.4.2 2023年7月15日
0.3.0 2023年6月24日
0.2.1 2023年6月10日
0.1.0 2023年5月27日

#1842 in 过程宏

Download history 1547/week @ 2024-04-08 1477/week @ 2024-04-15 1346/week @ 2024-04-22 1119/week @ 2024-04-29 1391/week @ 2024-05-06 1221/week @ 2024-05-13 1276/week @ 2024-05-20 1672/week @ 2024-05-27 1883/week @ 2024-06-03 1983/week @ 2024-06-10 1654/week @ 2024-06-17 2022/week @ 2024-06-24 1302/week @ 2024-07-01 2051/week @ 2024-07-08 2208/week @ 2024-07-15 1617/week @ 2024-07-22

7,345 每月下载量
用于 15 包(2 个直接使用)

MIT/Apache

30KB
411

默认结构体构建器

Crates.io Docs MIT/Apache 2.0 Build Status

为结构体每个字段生成构建器方法。它旨在用于实现 Default 的结构体。没有生成单独的构建器结构体,也不需要在结束时调用 build() 方法或 .unwrap()

此包由 leptos-use 包用于传递给各种函数的选项结构体。

安装

在您的项目文件夹中运行

cargo add default-struct-builder

使用方法

使用非常简单

use default_struct_builder::DefaultBuilder;

#[derive(DefaultBuilder, Default)]
pub struct SomeOptions {
    throttle: f64,

    #[builder(into)]
    offset: Option<f64>,

    #[builder(skip)]
    not_included: u32,
}

然后您可以使用结构体如下

let options = SomeOptions::default().offset(4.0);

assert_eq!(options.offset, Some(4.0));
assert_eq!(options.throttle, 0.0);
assert_eq!(options.not_included, 0);

泛型

该宏已准备好用于泛型结构体。

use default_struct_builder::DefaultBuilder;

#[derive(DefaultBuilder, Default)]
pub struct SomeOptions<T>
where
    T: Default,
{
    some_field: T,
}

文档注释

所有字段的文档注释都直接传递给其生成的设置方法。

它是如何工作的

派生宏生成以下代码

impl SomeOptions {
    // setter methods are given that consume `self` and return a new `Self` with the field value changed
    pub fn throttle(self, value: f64) -> Self {
        Self {
            throttle: value,
            ..self
        }
    }

    // because `into` was specified this method is generic and calls `.into()` when setting the value
    pub fn offset<T>(self, value: T) -> Self
    where
        T: Into<Option<f64>>,
    {
        Self {
            offset: value.into(),
            ..self
        }
    }

    // no method for field `not_included` because `skip` was specified
}

泛型

对于泛型字段,生成的方法稍微复杂一些,因为调用方法后类型参数的类型可能与之前不同。

让我们看看以下示例。

use default_struct_builder::DefaultBuilder;

#[derive(DefaultBuilder, Default)]
pub struct SomeOptions<T>
where
    T: Default,
{
    some_field: T,
    other_field: i16,
}

impl SomeOptions<f32> {
    pub fn new() -> Self {
        Self {
            some_field: 42.0,
            other_field: 0,
        }   
    }
}

这会生成以下设置方法。

impl<T> SomeOptions<T>
where
    T: Default,
{
    pub fn some_field<NewT>(self, value: NewT) -> SomeOptions<NewT>
    where
        NewT: Default,
    {
        SomeOptions::<NewT> {
            some_field: value,
            other_field: self.other_field,
        }
    }
}

fn main() {
   let options = SomeOptions::new()  // at first    SomeOptions<f32>
        .some_field("string");       // changed to  SomeOptions<&str>
}

如果不想让泛型字段能够改变泛型类型,可以对其进行 keep_type 注解。

#[derive(DefaultBuilder)]
struct SomeOptions<T> {
    #[builder(keep_type)]
    the_field: T,
}

这将生成一个标准的构建器方法,就像 T 没有泛型一样。

BoxRcArc

该宏检测一个字段是否为Box(或RcArc),并生成一个接受内部类型(不包括BoxRcArc)并在主体中添加外部类型的构建方法。

如果是Box<dyn Trait>,则构建方法将有一个类型为impl Trait的参数。对于RcArc也是如此。

如果您想防止这种自动解包,可以使用#[builder(keep_outer)]属性。

trait Test {}

#[derive(DefaultBuilder)]
struct SomeOptions {
    the_field: Box<dyn Test>,
    other_field: Rc<String>,

    #[builder(keep_outer)]
    keep: Box<String>,
}

这将生成以下代码

impl SomeOptions {
    pub fn the_field(self, value: impl Test + 'static) -> Self {
        Self {
            the_field: Box::new(value),
            ..self
        }   
    }

    pub fn other_field(self, value: String) -> Self {
        Self {
            other_field: Rc::new(value),
            ..self
        }
    }

    pub fn keep(self, value: Box<String>) -> Self {
        Self {
            keep: value,
            ..self
        }   
    }
}

对于更通用目的,请查看功能更强大的derive_builder crate

依赖项

~0.6–1MB
~25K SLoC