对于当前 Rust 版本 1.x
的答案:
有两种方法可以获得你想要的: 一个是未打包的闭包(unboxed closure),另一个是打包的闭包(boxed closure)。未打包的闭包非常快(大多数情况下,它们被内联),但它们会向结构体添加一个类型参数。打包的闭包在这里增加了一点自由度:它们的类型被一层间接性所抹去,但这会使它们变慢。
我的代码有一些示例函数,因此有点长,请谅解 ;)
未打包的闭包
完整代码:
struct Floor<F>
where F: for<'a> FnMut() -> &'a str
{
handler: Option<F>,
}
impl<F> Floor<F>
where F: for<'a> FnMut() -> &'a str
{
pub fn with_handler(handler: F) -> Self {
Floor {
handler: Some(handler),
}
}
pub fn empty() -> Self {
Floor {
handler: None,
}
}
pub fn set_handler(&mut self, handler: F) {
self.handler = Some(handler);
}
pub fn do_it(&mut self) {
if let Some(ref mut h) = self.handler {
println!("Output: {}", h());
}
}
}
fn main() {
let mut a = Floor::with_handler(|| "hi");
a.do_it();
let mut b = Floor::empty();
b.set_handler(|| "cheesecake");
b.do_it();
}
现在这段代码存在一些典型的问题:你不能简单地拥有多个Floor的Vec,并且每个使用Floor对象的函数都需要有自己的类型参数。另外,如果删除
b.set_handler(|| "cheesecake");这一行,则代码不会编译,因为编译器缺少对b的类型信息。
在某些情况下,您不会遇到这些问题 - 在其他情况下,您需要另一种解决方案。
Boxed closures
完整代码:
type HandlerFun = Box<for<'a> FnMut() -> &'a str>;
struct Floor {
handler: Option<HandlerFun>,
}
impl Floor {
pub fn with_handler(handler: HandlerFun) -> Self {
Floor {
handler: Some(handler),
}
}
pub fn empty() -> Self {
Floor {
handler: None,
}
}
pub fn set_handler(&mut self, handler: HandlerFun) {
self.handler = Some(handler);
}
pub fn do_it(&mut self) {
if let Some(ref mut h) = self.handler {
println!("Output: {}", h());
}
}
}
fn main() {
let mut a = Floor::with_handler(Box::new(|| "hi"));
a.do_it();
let mut b = Floor::empty();
b.set_handler(Box::new(|| "cheesecake"));
b.do_it();
}
这个程序运行速度略慢,因为每个闭包都需要进行堆内存分配,而调用装箱的闭包时通常需要进行间接调用(CPU 不喜欢间接调用...)。
但是 Floor
结构体没有类型参数,因此您可以拥有一个它们的 Vec
。 您还可以删除 b.set_handler(Box::new(|| "cheesecake"));
,程序仍然可以正常工作。
Box<FnMut(int, int) -> String + 'static>
。 - Vladimir Matveev