在Rust中传递闭包是非常简单的,但是当存储闭包以供重用时,有多种解决方案(使用通用函数类型,引用闭包或框,具有myTableData[indexPath.row]
生命周期的框?...)
虽然我使用不同类型的盒装类型多次混淆了这种情况,但请阅读类似的Q& A,甚至可能会有机会回答这个问题。我不知道如何处理这个问题,即使对于简单/明显的情况,也不是一个好的起点。
为了使问题更具体,使这个示例存储函数以便重用的好方法是什么,使用构建器模式存储将在以后调用的闭包。
'static
答案 0 :(得分:3)
对此的惯用解决方案是封装封装。虽然装箱闭包并稍后调用它会产生分配开销和动态调度开销,但在大多数情况下它可以忽略不计,MyAction
类型可以使用友好的错误消息轻松使用。
或者,不同的函数可以是MyAction
结构的通用字段,它存储闭包而没有间接。在某些情况下,这会产生巨大的加速,但由于更复杂的错误消息以及无法自由移动MyAction
个对象,这种类型的可用性会降低。
如果盒装版本在分析中清晰显示为慢,那么您可以转到通用版本。否则我建议继续使用易于使用的盒装版本。
带有'静态生命周期的盒子?
同样,为简单起见,您可以使用'static
生命周期,但是您的MyAction
结构只能存储不借用其环境的闭包。如果您在MyAction
结构上使用生命周期并将其转发到闭包,那么您将能够以通用参数为代价借用您的环境,这可能最终会导致MyAction
结构更难正确使用。
答案 1 :(得分:2)
为了完整起见,由于关闭所有权的一些语法并不明显,这是我尝试在问题中的代码的惯用/质朴版本。
(如果有任何问题,请直接评论或更新)。
'static
,这允许调用者在其环境中使用变量(请参阅问题中的num_other
使用)。而是在struct
上使用生命周期。使用盒装闭包继承容器结构生命周期的工作示例:
use std::boxed::Box;
struct MyActions<'a> {
num: i32,
times: i32,
update_fn: Option<Box<Fn(i32) -> i32 + 'a>>,
twiddle_fn: Option<Box<Fn(i32) -> i32 + 'a>>,
}
impl <'a> MyActions<'a> {
pub fn new(num: i32) -> Self {
return MyActions {
num: num,
times: 1,
update_fn: None,
twiddle_fn: None,
}
}
pub fn build(self) -> i32 {
let mut num = self.num;
if let Some(update_fn) = self.update_fn {
for _ in 0..self.times {
num = update_fn(num);
}
}
if let Some(twiddle_fn) = self.twiddle_fn {
for _ in 0..self.times {
num = twiddle_fn(num);
}
}
return num;
}
pub fn num_times(mut self, times: i32) -> Self {
self.times = times;
self
}
pub fn num_update<F>(mut self, func: F) -> Self
where
F: 'a,
F: Fn(i32) -> i32,
{
self.update_fn = Some(Box::new(func));
self
}
pub fn num_twiddle<F>(mut self, func: F) -> Self
where
F: 'a,
F: Fn(i32) -> i32,
{
self.twiddle_fn = Some(Box::new(func));
self
}
}
// no changes needed here
fn main() {
let act = MyActions::new(133);
let num_other: i32 = 4;
// builder pattern (currently executes immediately).
let result = act
.num_times(8)
.num_update(|x| x * 2 + num_other)
.num_twiddle(|x| (((x / 2) - 1) ^ (x + 1)) ^ num_other)
.build();
println!("done: {}", result);
// Lets say we would want this example to work,
// where 'times' is set after defining both functions.
let act = MyActions::new(133);
let result = act
.num_update(|x| x * 2 + num_other)
.num_twiddle(|x| (((x / 2) - 1) ^ (x + 1)) ^ num_other)
.num_times(8) // <-- order changed here
.build();
println!("done: {}", result);
}