我仍在内化 Rust 中的闭包以及如何最好地使用它们,所以这个问题可能有些模糊,并且可能会有一些愚蠢的子问题。我基本上是在寻找合适的习语,甚至可能改变我思考如何在 Rust 中做一些事情的方式。
Rust 书Cacher在关于闭包的章节中有一个简单的例子:
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它应该像这样使用:
let mut c = Cacher::new(|a| a);
let v1 = c.value(1);
Run Code Online (Sandbox Code Playgroud)
这是非常好的和有用的,但是如果我需要Cacher让它成为另一个结构的成员,例如(本着 Rust 书籍章节的精神),a WorkoutFactory? 由于Cacher由闭包的类型参数化,我被迫WorkoutFactory使用相同的闭包类型进行参数化。
我的理解正确吗?我猜是这样,Cacherstruct 结构取决于T计算的类型,因此 structWorkoutFactory结构必须取决于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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以完全像这样使用它Cacher:
let mut c = BCacher::new(|a| a);
let v1 = c.value(1);
Run Code Online (Sandbox Code Playgroud)
...几乎:('static'注释意味着我不能这样做:
let x = 1;
let mut c = BCacher::new(|a| a + x);
Run Code Online (Sandbox Code Playgroud)
因为关闭可能会活得更久x。不幸的是,盒装版本不再可能使用非盒装版本。
此外,此版本效率较低,需要取消引用Box(正确吗?),并且 RAM 访问速度较慢。在大多数情况下,差异很可能可以忽略不计,但仍然......
我可以用生命周期注释解决第一个问题:
struct BLCacher<'a> {
calculation: Box<Fn(u32) -> u32 + 'a>,
value: Option<u32>,
}
Run Code Online (Sandbox Code Playgroud)
但现在我又回到Cacher了类型参数以及由此带来的所有令人不快的后果。
这似乎是一个不幸的情况。我有两种在结构中存储闭包的方法,每种方法都有自己的一系列问题。比方说,我愿意住在一起,并作为真棒虚构的作者Cacher箱子,我想呈现的用户都的实现Cacher,在拆箱Cacher和装箱BCacher。但我不想写两次实现。什么是最好的方法 - 如果有的话 - 使用现有的Cacher实现来实现BCacher?
在相关说明中(甚至可能是同一个问题),让我们假设我有一个
struct WorkoutFactory<T>
where
T: Fn(u32) -> u32,
{
cacher: Cacher<T>,
}
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以在GymFactory不包含类型参数的情况下实现- 出于私人目的 -WorkoutFactory带有类型参数,可能存储在Box?
很长的问题,抱歉。来自 Scala,在 Rust 中使用闭包并不那么简单。我希望我已经解释了我尚未找到满意答案的挣扎。
抱歉,不是完整的答案,但在这段代码中:
let x = 1;
let mut c = BCacher::new(|a| a + x);
Run Code Online (Sandbox Code Playgroud)
为什么不将其更改为:
let x = 1;
let mut c = BCacher::new(move |a| a + x);
Run Code Online (Sandbox Code Playgroud)
这样函子将吸收并拥有“x”,因此不会有任何对它的引用,这有望解决所有其他问题。
| 归档时间: |
|
| 查看次数: |
750 次 |
| 最近记录: |