8 个版本 (4 个破坏性更改)
0.5.0 | 2023 年 5 月 8 日 |
---|---|
0.4.1 | 2023 年 5 月 6 日 |
0.3.0 | 2023 年 4 月 8 日 |
0.2.1 | 2023 年 4 月 4 日 |
0.1.3 | 2023 年 4 月 2 日 |
#1811 in Rust 模式
在 framy 中使用
21KB
321 行
类型安全构建器模式
不可故障的编译时检查构建器,适用于您的结构体。
不再需要担心您的构建器上的 build
调用是否会返回 Ok
或 Err
。也许你忘记设置一个字段? typesafe-builders
通过使用 Rust 类型系统来确保正确的使用。
示例
use typesafe_builders::prelude::*;
fn main() {
#[derive(Builder)]
struct Point {
#[builder(constructor)]
x: u8,
y: u8,
#[builder(optional)]
z: Option<u8>,
}
// `builder` requires `x` since it is marked as `constructor`.
let builder = Point::builder(1);
// These do not compile:
// partial.x(6); // `x` is already set
// partial.build(); // `y` is not set
// `build` is only available once all required fields are set:
let result = builder.y(2).build();
assert_eq!(result.x, 1);
assert_eq!(result.y, 2);
assert_eq!(result.z, None);
}
已知缺点
我只推荐在 内部使用。最好不要将这些构建器类型作为你的 crate 的 API,因为它们看起来非常丑陋且冗长。例如
use typesafe_builders::prelude::*;
#[derive(Builder)]
struct Point {
x: u8,
y: u8,
z: u8,
}
// Ugly type name here... and it only gets worse for const-generics etc.
fn preset() -> GenericPointBuilder<false, false, true> {
Point::builder().z(0)
}
fn main() {
let partial = preset();
let point = partial.x(1).y(2).build();
}
如果你知道如何改进这个,请打开一个 MR/Issue。
字段属性
属性可以组合。那些不能一起工作的将在编译时抛出显式错误。重复总是错误。
可选
字段可以设置,但不必设置。需要字段类型为 Default
。
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct {
#[builder(optional)]
x: u8,
}
fn main() {
// without x
Struct::builder().build();
// with x
Struct::builder().x(4).build();
}
构造函数
在构建器构造时要求设置字段。
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct {
#[builder(constructor)]
x: u8,
}
fn main() {
Struct::builder(4).build();
// does not work:
// Struct::builder(4).x(5).build();
}
降级
将类型降级为其第一个泛型。简化了对 Option
、Box
等的使用。要求降级后的类型可以被 into
成原始类型。对所有只有一个泛型参数的类型都有效。
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct {
#[builder(decay)]
x: Option<u8>,
}
fn main() {
// Use `4` of `Some(4)`
Struct::builder().x(4).build();
}
它是如何工作的?
常量泛型单热位字段。你得到的是类似这样的东西
pub struct Builder<const x_set: bool, const y_set: bool> {
x: Option<u8>,
y: Option<u8>,
}
impl<const y_set: bool> Builder<false, y_set> {
fn set_x(self, x: u8) -> Builder<true, y_set,> {
unimplemented!()
}
}
impl<const x_set: bool> Builder<x_set, false> {
fn set_y(self, y: u8) -> Builder<x_set, true> {
unimplemented!()
}
}
// The build function is only available once all fields are set:
impl Builder<true, true> {
fn build() {
}
}
更多示例
生命周期
它们按预期工作
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct<'a, 'b, 'c> {
x: &'a Box<&'b Option<&'c str>>, // yikes
}
fn main() {
Struct::builder().x(&Box::new(&Some("hi"))).build();
}
泛型
按预期工作,但尚未支持默认值。
mod other {
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct<T: Clone> {
y: Option<T>,
}
}
fn main() {
other::Struct::<u8>::builder().y(Some(4)).build();
}
常量泛型
按预期工作,但尚未支持默认值。
mod other {
use typesafe_builders::prelude::*;
#[derive(Builder)]
pub struct Struct<const LEN: usize> {
x: [u8; LEN],
}
}
fn main() {
other::Struct::<1>::builder().x([1]).build();
}
待办事项
- 生命周期
- 泛型
- 界限
- 带有默认值
- 常量泛型
- 带有默认值
- 添加
optional
字段。 - 添加
rename
字段属性。 - 添加
constructor
或类似功能,以便在builder
函数中直接添加必填参数。 - 添加
Into
或类似功能以进行类型转换。 - 自动添加以
Some
传递选项的方式。 - 清理
依赖项
~275–730KB
~17K SLoC