1 个不稳定版本
0.1.0 | 2022 年 6 月 21 日 |
---|
#2568 在 Rust 模式
8KB
60 行
Template.rs
一个用于创建符合惯用、声明式、构建器样式的 Rust 库,使用结构字面量语法。
无需宏函数!
如何使用
要创建一个模板,就像创建一个构建器一样,你必须考虑以下因素
- 所有参数
- 模板的默认状态
- 模板构建成什么
- 与其他对象的关系
你可以使用 #[template]
注释来定义你的模板模型结构体,以及 Template
特性。
1. 定义参数
只需在具有所有参数作为其字段的 struct 上使用 #[template]
注释即可
#[template]
pub struct Box {
orientation: Orientation,
spacing: i32,
padding: i32,
margin: i32,
}
#[template]
pub struct Button {
padding: i32,
margin: i32,
style: StyleDescriptor,
text: String
}
2. 模板的默认状态
默认情况下,此库通过 #[derive(Default)]
定义模板的默认状态。也计划提供自定义 Default
实现。
3. 模板构建成什么
使用 Template
特性来定义模板构建成什么,以及如何构建
impl Template for Box {
type Output = some_other_lib::Box;
fn define(self) -> Self::Output {
let mut this = some_other_lib::Box::new();
this.padding = self.padding;
//...
this
}
}
impl Template for Button {
type Output = some_other_lib::Button;
fn define(self) -> Self::Output {
let mut this = some_other_lib::Button::new();
this.padding = self.padding;
//...
this
}
}
与其他对象的关系
通过模板的目标对象进行依赖注入,定义不同的默认状态。
trait Container {
fn child<T, W>(&self) -> T
where T: Template<Output = W>,
W: some_other_lib::Widget;
}
impl Container for some_other_lib::Box {
fn child<T, W>(&self) -> T
where T: Template<Output = W>,
W: some_other_lib::Widget
{
let this = self.clone();
let out = Button::default(); // The template
out.on_create(move |w| this.add(w)); // provided by the #[template] annotation
out
}
}
使用模板
所有注释过的模板实现了以下特性,用于构建目标类型
for<A,F: FnOnce(Self::Output) ->A> FnOnce(F) ->A
FnOnce() -> Self::Output
这些特性可以在结构字面量之后以“柯里化”的方式调用。
这是一个简单示例,展示了惯用模板
Box {
orientation: Orientation::HORIZONTAL,
padding: 6,
spacing: 6,
..Default::default()
} (|w| {
Box {
orientation: Orientation::VERTICAL,
spacing: 6,
..w.child()
} (|w| {
Button {
text: "Column btn 1",
..w.child()
}();
// Function call constructs button
// and adds it to the box as per the
// ..w.child() injection directive
Button {
text: "Column btn 2"
..w.child()
}();
}); // function call runs the lambda argument
// on the output and then returns it
Button {
text: "Big btn",
..w.child()
}();
})
// expected result:
// |--------------|---------|
// | Column btn 1 | |
// |--------------| Big Btn |
// | Column btn 2 | |
// |--------------|---------|
如果你不想使用直接函数调用,可以使用以下等效方法
fn build<A>(self, F:impl FnOnce(Self::Output)-> A) ->A
fn create(self) -> Self::Output
Box {
orientation: Orientation::HORIZONTAL,
padding: 6,
spacing: 6,
..Default::default()
}.build(|w| { // creations with lambdas use the "build" method
Button {
text: "Hello World",
..w.child()
}.create(); // creations without arguments use the "create" method
})
当前问题和未来计划
- 允许用户为模板定义自定义默认状态
- 创建一个
Templatable
特性,将模板的输出与其模板关联起来,这样您就无需自行关联。例如。
trait Templatable {
type New: Template<Output = Self>;
}
// ...so that
use some_other_lib::Box;
Box::New {
//...
} ();
- 目前一些类型分析器不考虑
std::ops::FnOnce
实现,因此它们会自动将Struct { /*...*/ } ( /*...*/ )
语法标记为错误,尽管按照std::ops::FnOnce
特性定义,这些语法是完全合法和正确的。例如,在jetbrains Rust插件中。在这些问题解决之前,您可以选择使用不同的分析器,或者使用替代的.build()
和.create()
方法。
依赖项
~7KB