我仍在内部化Rust中的闭包以及如何最好地使用它们,所以这个问题可能有点模糊,也许会有愚蠢的子问题。我基本上都在寻找合适的习语,甚至可能改变我对如何在Rust中做一些事情的思考方式。
Rust书中有一个简单的Cacher
示例chapter on closures:
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
它应该像这样使用:
let mut c = Cacher::new(|a| a);
let v1 = c.value(1);
这是非常好的和有用的,但是如果我需要让这个Cacher
成为另一个结构的成员,比如说(根据Rust书的章节精神),WorkoutFactory
?由于Cacher
由闭包类型参数化,因此我被迫使用相同的闭包类型参数化WorkoutFactory
。
我的理解是否正确?我想是的,Cacher
结构结构取决于计算的类型T
,因此结构WorkoutFactory
结构必须依赖于Cacher
的类型。一方面,这感觉就像关闭Rust如何工作的自然,不可避免和完全合理的结果,另一方面它意味着
WorkoutFactory
可以包含在另一个也被T
强制参数化的结构中,该结构可以包含在另一个结构中,...... - 封闭类型像瘟疫一样传播。或许其他T
来自成员层次结构的深处,顶级结构的签名可能变得怪异。WorkoutFactory
中涉及一些缓存的事实应该只是一个实现细节,或许缓存甚至在版本2.0中添加,但类型参数在WorkoutFactory
的公共接口中可见并需要加以考虑。看似实现细节现在是界面的一部分,不好:(有没有办法在不改变Cacher
签名的情况下解决这些问题?其他人如何应对这种情况?
如果我想摆脱类型参数,我可以Box
关闭。我想出了以下代码:
struct BCacher {
calculation: Box<Fn(u32) -> u32>,
value: Option<u32>,
}
impl BCacher {
fn new<T: Fn(u32) -> u32 + 'static>(calculation: T) -> BCacher {
BCacher {
calculation: Box::new(calculation),
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
我可以像Cacher
一样使用它:
let mut c = BCacher::new(|a| a);
let v1 = c.value(1);
... 几乎 :( 'static'
注释意味着我不能这样做:
let x = 1;
let mut c = BCacher::new(|a| a + x);
因为关闭可能比x
更长。这是不幸的,盒装版本不再可能使用非盒装版本。
此外,这个版本的效率较低,有必要取消引用Box
(这是正确的吗?),并且RAM访问速度很慢。在大多数情况下,这种差异很可能是微不足道的,但仍然是......
我可以用生命周期注释解决第一个问题:
struct BLCacher<'a> {
calculation: Box<Fn(u32) -> u32 + 'a>,
value: Option<u32>,
}
但现在我回到了Cacher
,带有类型参数和所有令人不快的后果。
这似乎是一个不幸的情况。我有两种方法在结构中存储闭包,每种方法都有自己的一组问题。假设我愿意接受这一点,作为令人敬畏的虚构Cacher
箱子的作者,我想向用户展示{em>两个的Cacher
实现,未装箱的Cacher
和装箱的BCacher
。但我不想两次编写实现。什么是最好的方法 - 如果有的话 - 使用现有的Cacher
实现来实现BCacher
?
在相关的说明中(也许它甚至是同一个问题),让我们假设我有一个
struct WorkoutFactory<T>
where
T: Fn(u32) -> u32,
{
cacher: Cacher<T>,
}
有没有办法实现GymFactory
没有类型参数,包含 - 出于私人目的 - WorkoutFactory
带有类型参数,可能存储在Box
?
一个很长的问题,对不起。来自Scala,使用闭包在Rust中不那么简单。我希望我已经解释了我尚未找到满意答案的挣扎。