1个不稳定版本
0.1.0 | 2023年1月7日 |
---|
#7 在 #named-fields
17KB
193 行
动态struct
为具有命名字段的struct创建基于推送的响应式属性的derive宏(仅限于具有命名字段的struct)。
为什么是推送式的?
懒的基于轮询的响应式系统通常需要包装值并添加RefCells或标志来缓存和更新值。基于事件的系统需要一个订阅模型。
添加基于推送的更改传播的管道是通过编译时宏完成的,生成的代码可以在编译期间内联,在运行时成为零成本抽象(就像在依赖关系更改时手动重新计算动态属性一样)
类型也可以保持不变,无需包装和解引用。
如何使用
1) 将其添加为Cargo文件中的依赖项
[dependencies]
dynamic-struct = "0.1"
2) 将derive宏添加到struct中并标记动态属性
use dynamic_struct::Dynamic;
#[derive(Dynamic)]
struct Demo {
a: u32,
b: u32,
#[dynamic((a, b), calculate_c)]
c: u32,
}
impl Demo {
fn calculate_c(&mut self) {
self.c = self.a + self.b
}
}
属性的属性具有以下结构
#[dynamic(tuple of dependent property names, name of local method name)]
局部方法必须具有与以下匹配的调用签名:fn name(&mut self)
.
3) 使用生成的mutate函数更新属性
fn main() {
let demo = Demo { a: 1, b: 2, c: 3 };
dbg!(demo.c); //3
demo.update_a(7);
dbg!(demo.c); //9
}
工作原理
1) 创建函数以在属性更改时发出信号,其中填充了应调用的方法。
impl Demo {
#[inline]
pub fn updated_a(&mut self) {
self.update_c();
}
}
注意:不传播更改的属性将仍然创建,但将为空。
2) 为每个属性创建一个函数来更新属性
对于非动态属性,可以通过匹配字段类型的参数设置值,然后调用上述列出的字段更新函数。
impl Demo {
#[inline]
pub fn update_a(&mut self, a: u32) {
self.a = a;
self.updated_a();
}
}
对于动态属性,通过调用指定的动态函数设置值,然后调用上述列出的字段更新函数。
impl Demo {
#[inline]
pub fn update_c(&mut self) {
self.calculate_c();
self.updated_c();
}
}
注意:请小心不要创建循环依赖!
配置
可以通过声明结构体属性并重写前缀/后缀来自定义生成的函数名称。例如
#[derive(Dynamic)]
#[dynamic(setter_prefix = "set_", setter_suffix = "_value")]
struct MyStruct {
a: u32,
b: u32,
}
fn main() {
let test = MyStruct { a: 1, b: 2 };
test.set_a_value(3);
test.set_b_value(4);
}
可以指定的属性包括
名称 | 类型 | 注释 |
---|---|---|
updated_prefix | 字符串 | 更新方法的名称前缀 |
updated_suffix | 字符串 | 更新方法的名称后缀 |
setter_prefix | 字符串 | 设置方法的前缀(非动态字段) |
setter_suffix | 字符串 | 设置方法的名称后缀(非动态字段) |
update_prefix | 字符串 | 更新方法的前缀(动态字段) |
update_suffix | 字符串 | 更新方法的后缀(动态字段) |
依赖项
~2MB
~44K SLoC