Struct::new
没有任何与 F
相关的参数,因此编译器无法推断应该使用什么类型来替代 F
。如果稍后调用了一个使用了 F
的方法,那么编译器就会利用这些信息来确定 Struct
的具体类型。例如:
use std::hash::Hash;
use std::collections::HashMap;
pub struct Struct<T, F>
where T: Eq,
T: Hash,
F: Fn() -> T,
{
hash_map: HashMap<T, F>,
value: T,
}
impl<T, F> Struct<T, F>
where T: Eq,
T: Hash,
F: Fn() -> T,
{
pub fn new(init_value: T) -> Struct<T, F> {
Struct {
hash_map: HashMap::new(),
value: init_value,
}
}
pub fn set_fn(&mut self, value: T, func: F) {
self.hash_map.insert(value, func);
}
}
fn main() {
let mut a = Struct::new(0);
a.set_fn(0, || 1);
}
但是这里存在一个问题。如果我们再次调用 set_fn
,并传入不同的闭包函数:
fn main() {
let mut a = Struct::new(0);
a.set_fn(0, || 1);
a.set_fn(1, || 2);
}
然后我们会得到一个编译器错误:
error[E0308]: mismatched types
--> <anon>:33:17
|
33 | a.set_fn(1, || 2);
| ^^^^ expected closure, found a different closure
|
= note: expected type `[closure@<anon>:32:17: 32:21]`
= note: found type `[closure@<anon>:33:17: 33:21]`
note: no two closures, even if identical, have the same type
--> <anon>:33:17
|
33 | a.set_fn(1, || 2);
| ^^^^
help: consider boxing your closure and/or using it as a trait object
--> <anon>:33:17
|
33 | a.set_fn(1, || 2);
| ^^^^
正如编译器所述,每个闭包表达式都定义了一个全新的类型并返回该类型。然而,通过你定义
Struct
的方式,你强制
HashMap
中的所有函数具有相同的类型。这真的是你想要的吗?
如果你想将
T
的不同值映射到可能不同类型的闭包,则需要使用特征对象而不是泛型,正如编译器建议的那样。如果你想让结构体拥有闭包,则必须在对象类型周围使用
Box
。
pub struct Struct<T>
where T: Eq,
T: Hash,
{
hash_map: HashMap<T, Box<Fn() -> T + 'static>>,
value: T,
}
set_fn
可以像这样:
pub fn set_fn<F: Fn() -> T + 'static>(&mut self, value: T, func: F) {
self.hash_map.insert(value, Box::new(func));
}
T + 'static
的语法。这是什么意思(这样我就可以阅读相应的文档了)?这与生命周期有关吗? - lesurp'static
是一个 _lifetime bound_。它限制了实现Fn() -> T
的类型中借用指针的生命周期。'static
意味着该类型不能包含比'static
生命周期更短的任何借用指针(没有借用指针的类型是可以的)。如果需要更多的灵活性,可以在Struct
上引入一个生命周期参数 (<'a, T>
) 并使用它。 - Francis Gagné