在Rust 1.0之前,我可以使用这种过时的闭包语法编写结构:
struct Foo {
pub foo: |usize| -> usize,
}
现在我可以这样做:
struct Foo<F: FnMut(usize) -> usize> {
pub foo: F,
}
但是我创建的Foo
对象的类型是什么?
let foo: Foo<???> = Foo { foo: |x| x + 1 };
我也可以使用参考:
struct Foo<'a> {
pub foo: &'a mut FnMut(usize) -> usize,
}
我认为这比较慢,因为
FnMut
类型没有专门化答案 0 :(得分:25)
使用||
语法的旧式闭包是对存储在堆栈中的闭包的引用,使它们等同于&'a mut FnMut(usize) -> usize
。旧式proc
是堆分配的,等同于Box<dyn FnOnce(usize) -> usize>
(您只能调用proc
一次)。
至于您在第三个代码段中使用的类型,不是一个;闭包类型是匿名的,不能直接命名。相反,你要写:
let foo = Foo { foo: |x| x + 1 };
如果您在需要的上下文中编写代码以指定您想要Foo
,则可以写下:
let foo: Foo<_> = Foo { foo: |x| x + 1 };
_
告诉类型系统为您推断实际的泛型类型。
关于使用的一般经验法则,按降序排列:
struct Foo<F: FnMut(usize) -> usize>
。这是最有效的,但它确实意味着特定的Foo
实例只能存储一个闭包,因为每个闭包都有不同的具体类型。&'a mut dyn FnMut(usize) -> usize
。有一个指针间接,但现在你可以存储对任何具有兼容调用签名的闭包的引用。Box<dyn FnMut(usize) -> usize>
。这涉及在堆上分配闭包,但你不必担心生命周期。与引用一样,您可以使用兼容签名存储任何闭包。答案 1 :(得分:2)
使用更多代码补充现有答案,以进行演示:
使用通用类型:
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
}
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
fn main() {
let foo = Foo {
foo: Box::new(|a| a + 1),
};
(foo.foo)(42);
}
struct Foo<'a> {
pub foo: &'a dyn Fn(usize) -> usize,
}
fn main() {
let foo = Foo { foo: &|a| a + 1 };
(foo.foo)(42);
}
struct Foo {
pub foo: fn(usize) -> usize,
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
}
我创建的
Foo
对象的类型是什么?
这是一种无法命名的自动生成的类型。
我也可以使用较慢的引用,因为指针不专门化
也许吧,但是在呼叫者身上会容易得多。
另请参阅: