7 个版本

0.1.6 2023 年 1 月 30 日
0.1.5 2023 年 1 月 29 日
0.1.2 2022 年 12 月 26 日

982Rust 模式

每月 31 次下载

MIT/Apache

14KB
127

工程师

Build and Test Rust

Engineer 是基于 Optional 的大师级构建者。

它仅生成一个数据模型对应的 Engineer (Builder) 类。

安装

将以下作为依赖项添加

[dependencies]
engineer = "0.1.3"

入门

use engineer::Engineer;

#[derive(Engineer)]
struct Identity {
    id: usize,
    username: String,
    first_name: Option<String>,
    last_name: Option<String>,
    lang_code: Option<String>,
}

可选字段在初始化期间不是必需的。

// Option fields are set to None.
let identity = Identity::engineer(0, "immmdreza".to_string()).done();

但您也可以为 Option 字段设置一个值。

let identity = Identity::engineer(0, "immmdreza".to_string()) // IdentityEngineer
    .first_name("Arash".to_string()) // IdentityEngineer
    .last_name("Tofani".to_string()) // IdentityEngineer
    .done(); // Identity

以上是基础知识,但您可以进行一些定制。

定制

Engineer 结构名称

默认情况下,Engineer 结构名称为 {struct}Engineer (IdentityEngineer for Identity),但您可以更改它。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(engineer_name = "IdentityBuilder")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::engineer(0, "immmdreza".to_string()) // IdentityBuilder
        .first_name("Arash".to_string()) // IdentityBuilder
        .last_name("Tofani".to_string()) // IdentityBuilder
        .done(); // Identity

Builder 函数名称

默认情况下,builder 函数名称为 engineer,但您知道吗?

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(builder_func = "builder")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::builder(0, "immmdreza".to_string())
    // ~~~ sniff ~~~

您希望将其用作 new 函数

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(builder_func = "new")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza".to_string())
    // ~~~ sniff ~~~

这可以简化为特殊 new 名称作为 builder 函数

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
}

Options 的默认值

您可以为选项字段设置默认值。

如果未设置其他值,则使用此值。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
    #[engineer(default_value = r#"String::from("fa")"#)]
    lang_code: Option<String>,
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza".to_string());

    identity.lang_code // Some("fa")

或者,您可以使用 default 来设置 Some(Default::default) 替代 None,如果未提供任何其他值。

    // ~~~ sniff ~~~
    #[engineer(default)]
    luck_number: Option<i32>, // Some(0)
    // ~~~ sniff ~~~

重打字

您可以更改 builder 过程中请求的类型。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
    #[engineer(retype(to = "impl Into<String>", re = ".into()"))]
    //                      ^                         ^
    //                      | Requested type in public.
    //                                                |
    //                                                | How we recover to original type.
    username: String,
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza"); // .to_string() is not needed.
    // ~~~ sniff ~~~

或者,对于 str 重打字(如上面的示例),您可以使用缩写 str_retype

    // ~~~ sniff ~~~
    #[engineer(str_retype)]
    username: String,
    // ~~~ sniff ~~~

您还可以全局使用重打字。

#[derive(Engineer)]
#[engineer(new, retype(from = "String", to = "impl Into<String>", re = ".into()"))]
struct Identity {
    // ~~~ sniff ~~~
}

或者,对于 String 重打字

#[derive(Engineer)]
#[engineer(new, str_retype)]
struct Identity {
    // ~~~ sniff ~~~
}

以上两个代码都将所有 String 字段重打字为公共 API 中的 impl Into<String>

最终结果

#[derive(Engineer)]
#[engineer(new, str_retype)]
struct Identity {
    id: usize,
    username: String,
    first_name: String,
    last_name: Option<String>,
    #[engineer(str_retype, default_value = "\"fa\".to_string()")]
    lang_code: Option<String>,
}

fn print_identity(ident: impl Into<Identity>) {
    let ident: Identity = ident.into();
    println!("{ident:#?}");
}

fn main() {
    let ident = Identity::new(1, "immmdreza", "Arash").last_name("Tofani");

    print_identity(ident);
    // Identity {
    //     id: 1,
    //     username: "immmdreza",
    //     first_name: "Arash",
    //     last_name: Some(
    //         "Tofani",
    //     ),
    //     lang_code: Some(
    //         "fa",
    //     ),
    // }
}

更多关于特质的介绍

这个crate有两个主要特性:Builder<T> where T: EngineerEngineer

Engineer特性有两个关联类型:ParamsBuilder

  • Params是你需要的字段类型(不是Option<_>的字段)的元组。
  • Builder是Builder/Engineer类的类型。

使用Engineer宏,将使你的数据类实现Engineer特性,并创建一个实现Builder<T>的Builder结构体(通常命名为{struct_name}Engineer - 我正在考虑重命名),其中T是你的自定义结构。

这使你能够在这些特性周围做一些泛型操作,例如

fn build_any<E>(required: E::Params) -> E
where
    E: Engineer,
{
    E::build(required)
}

// Or

fn get_builder<E>(required: E::Params) -> E::Builder
where
    E: Engineer,
{
    E::builder(required)
}

注意,E::Params是一个元组。

如果你所有的所需字段(E::Param)都实现了Default,那么另一个函数build_default将可在你的结构体上使用,它创建一个不需要任何输入的默认实例。

此外,Engineer特性有两个常量字段

- const NORMAL_FIELDS: usize;
- const OPTIONAL_FIELDS: usize;

🧀

依赖项

~2MB
~42K SLoC