#derive-builder #builder-pattern #builder #macro-derive #setter #struct #derive

no-std derive_builder_fork_arti

Rust 宏,用于自动为任意结构体实现 builder 模式

1 个不稳定版本

使用旧的 Rust 2015

0.11.2 2022 年 5 月 6 日

#1244Rust 模式

Download history 1826/week @ 2024-03-13 2558/week @ 2024-03-20 1823/week @ 2024-03-27 2068/week @ 2024-04-03 1923/week @ 2024-04-10 1394/week @ 2024-04-17 1874/week @ 2024-04-24 1711/week @ 2024-05-01 1406/week @ 2024-05-08 1728/week @ 2024-05-15 1492/week @ 2024-05-22 1751/week @ 2024-05-29 1341/week @ 2024-06-05 2030/week @ 2024-06-12 2667/week @ 2024-06-19 2420/week @ 2024-06-26

8,826 每月下载次数
用于 34 个 crate(17 直接使用)

MIT/Apache

43KB
74

Build Rust version Documentation Latest version All downloads Downloads of latest version

Builder 模式派生

Rust 宏,用于自动为任意结构体实现 builder 模式。一个简单的 #[derive(Builder)] 会为你的结构体 Foo 生成一个 FooBuilder,包含所有 setter 方法和一个 build 方法。

这是一个分支版本

此版本的 derive_builder 有一个额外的 sub_builder 功能,该功能 尚未被上游接受。我们可能会添加更多额外的功能。

在其他方面,这个分支可能落后于上游 crate。

它如何工作

#[macro_use]
extern crate derive_builder;

#[derive(Default, Builder, Debug)]
#[builder(setter(into))]
struct Channel {
    token: i32,
    special_info: i32,
    // .. a whole bunch of other fields ..
}

fn main() {
    // builder pattern, go, go, go!...
    let ch = ChannelBuilder::default()
        .special_info(42u8)
        .token(19124)
        .build()
        .unwrap();
    println!("{:?}", ch);
}

注意,我们没有编写任何关于 ChannelBuilder 的定义或实现。相反,derive_builder crate 在编译时根据 #[derive(Builder)] 生成必要的代码。

这是你不需要编写的自动生成的样板代码。:-)

#[derive(Clone, Default)]
struct ChannelBuilder {
    token: Option<i32>,
    special_info: Option<i32>,
}

#[allow(dead_code)]
impl ChannelBuilder {
    pub fn token<VALUE: Into<i32>>(&mut self, value: VALUE) -> &mut Self {
        let mut new = self;
        new.token = Some(value.into());
        new
    }
    pub fn special_info<VALUE: Into<i32>>(&mut self, value: VALUE) -> &mut Self {
        let mut new = self;
        new.special_info = Some(value.into());
        new
    }
    fn build(
        &self,
    ) -> Result<Channel, ChannelBuilderError> {
        Ok(Channel {
            id: match self.id {
                Some(ref value) => Clone::clone(value),
                None => {
                    return Err(
                        Into::into(
                            ::derive_builder::UninitializedFieldError::from("id"),
                        ),
                    )
                }
            },
            token: match self.token {
                Some(ref value) => Clone::clone(value),
                None => {
                    return Err(
                        Into::into(
                            ::derive_builder::UninitializedFieldError::from("token"),
                        ),
                    )
                }
            },
            special_info: match self.special_info {
                Some(ref value) => Clone::clone(value),
                None => {
                    return Err(
                        Into::into(
                            ::derive_builder::UninitializedFieldError::from("special_info"),
                        ),
                    )
                }
            },
        })
    }
}

注意:本文档为便于阅读而进行了编辑。生成的代码不假设如 Into 这样的特性在作用域内,并且使用完整路径来访问它们。

开始使用

只需三个步骤即可完成

  1. derive_builder 添加到您的 Cargo.toml 文件中,可以是手动添加或者使用 cargo-edit
  • cargoadd derive_builder
  1. 添加 use derive_builder::Builder;
  2. 使用 #[derive(Builder)] 注释您的结构体

用法和特性

  • 链式调用:默认情况下,设置器调用可以链式调用,因为它们会消耗并返回 &mut self
  • 构建器模式:您可以通过在结构体(或字段)前加上 #[builder(pattern = "owned")]#[builder(pattern = "immutable")] 来选择其他构建器模式。
  • 可扩展性:您仍然可以定义自己的构建器结构体实现并定义额外的方法。只需确保它们的名称与设置器和构建方法不同即可。
  • 文档和属性:可以通过注释相应的字段来注释设置器方法。同样,#[cfg(...)]#[allow(...)] 属性也应用于设置器方法。
  • 隐藏字段:您可以通过在各个字段上使用 #[builder(setter(skip))] 跳过设置器。
  • 设置器可见性:您可以通过在结构体前加上 #[builder(private)] 来选择私有设置器。
  • 设置器类型转换:使用 #[builder(setter(into))],设置器方法将对输入类型进行泛型处理 - 您可以为字段类型提供实现了 Into 特性的每个参数。
  • 设置器剥离选项:使用 #[builder(setter(strip_option))],设置器方法将以 T 作为参数类型来处理 Option<T> 类型的字段。
  • 集合设置器:将 #[builder(setter(each(name = "method_name")))] 添加到实现了 DefaultExtend 的字段类型,将为该字段生成一个设置器,该设置器将项目添加到该字段的构建器集合中。这些设置器也可以对这些 Into<T> 特性进行泛型处理,如下所示: #[builder(setter(each(name = "foo", into)))]
  • 构建器字段可见性:您可以使用 #[builder(field(private))]..(public),来设置您的构建器字段的可见性。
  • 泛型结构体:也受到支持,但如果您还启用了设置器类型转换,则 不能 使用名为 VALUE 的类型参数。
  • 默认值:您可以使用 #[builder(default)] 来委托给 Default 实现或通过 = ".." 使用任何显式值。这在结构体和字段级别都适用。
  • 预构建验证:您可以使用 #[builder(build_fn(validate = "path::to::fn"))] 在目标结构体生成之前添加您自己的验证。
  • 抑制构建方法:您可以使用 #[builder(build_fn(skip))] 来禁用自动实现的构建方法并自行提供。
  • 自定义构建方法错误类型:您可以使用 #[builder(build_fn(error = "path::to::Error"))] 让构建器返回您选择的错误类型。默认情况下,宏将在构建器旁边发出错误类型。
  • 构建器推导:您可以使用 #[builder(derive(Trait1, Trait2, ...))] 来让构建器添加额外的特性。所有构建器都推导 DefaultClone 特性,因此您不应在此属性中声明这些。
  • 透传属性:使用 #[builder_struct_attr(...)]#[builder_impl_attr(...)]#[builder_field_attr(...)]#[builder_setter_attr(...)] 来声明将被添加到生成的构建器相关部分的属性。
  • no_std 支持:只需在你的结构体中添加 #[builder(no_std)],并在你的 crate 中添加 extern crate alloc

有关更多信息示例,请参阅我们的 文档

注意事项

  • Cargo.toml 中重命名 derive_builder 不受支持。
  • 元组和单位结构体不受支持,因为它们没有字段名称。我们无意支持它们。
  • 在定义泛型结构体时,您不能使用 VALUE 作为泛型参数,因为这正是所有设置器所使用的。

文档

所有功能的详细说明和故障排除技巧。您还可以找到不同构建模式讨论。

变更日志

是的,我们保留变更日志。

许可证

根据您的选择,许可为以下之一

贡献

除非您明确声明,否则您有意提交的任何贡献,根据 Apache-2.0 许可证定义,应如上所述双重许可,不附加任何额外条款或条件。

依赖关系

~2MB
~45K SLoC