7 个不稳定版本
0.4.0 | 2024 年 3 月 7 日 |
---|---|
0.3.1 | 2023 年 11 月 27 日 |
0.3.0 | 2023 年 5 月 16 日 |
0.2.2 | 2023 年 4 月 17 日 |
0.1.0 | 2022 年 10 月 15 日 |
#23 在 缓存
5,090 每月下载量
在 33 个包 中使用 (21 个直接使用)
47KB
890 行
comemo
通过约束记忆化实现增量计算。
[dependencies]
comemo = "0.4"
一个 记忆化 函数会缓存其返回值,这样它就只需要对一组唯一的参数执行一次。这使其成为一个优秀的优化工具。然而,基本的记忆化相当有限。对于像增量编译器这样的更高级用例,它缺乏必要的粒度。考虑,例如,简单的 .calc
脚本语言。这种语言中的脚本由数字之和和引用其他 .calc
脚本的 eval
语句组成。一些例子包括
alpha.calc
:"2 + eval beta.calc"
beta.calc
:"2 + 3"
gamma.calc
:"8 + 3"
我们可以轻松编写一个计算 .calc
文件输出的解释器
/// Evaluate a `.calc` script.
fn evaluate(script: &str, files: &Files) -> i32 {
script
.split('+')
.map(str::trim)
.map(|part| match part.strip_prefix("eval ") {
Some(path) => evaluate(&files.read(path), files),
None => part.parse::<i32>().unwrap(),
})
.sum()
}
impl Files {
/// Read a file from storage.
fn read(&self, path: &str) -> String {
...
}
}
但是,如果我们想使这个解释器 增量,也就是说,只有当脚本或其依赖项发生变化时才重新计算脚本的结果,该怎么办?基本的记忆化无法帮助我们,因为解释器需要整个文件集作为输入——这意味着任何文件的变化都会使所有记忆化的结果无效。
这就是 comemo 发挥作用的地方。它实现了具有更细粒度访问跟踪的 约束记忆化。要使用它,我们只需
- 将
#[memoize]
属性添加到evaluate
函数。 - 将
#[track]
属性添加到Files
的 impl 块中。 - 将
files
参数包裹在 comemo 的Tracked
容器中。
这指示 comemo 记忆化评估并自动跟踪在记忆化调用期间的所有文件访问。因此,只要其依赖项保持不变,我们就可以重用 .calc
脚本评估的结果——即使其他文件发生变化。
use comemo::{memoize, track, Tracked};
/// Evaluate a `.calc` script.
#[memoize]
fn evaluate(script: &str, files: Tracked<Files>) -> i32 {
...
}
#[track]
impl Files {
/// Read a file from storage.
fn read(&self, path: &str) -> String {
...
}
}
有关完整示例,请参阅 examples/calc.rs
。
许可证
此软件包同时受 MIT 和 Apache 2.0 许可证的许可。
依赖项
~0.8–6.5MB
~31K SLoC