我正在尝试在Rust中创建这样的结构:
pub struct Struct<T, F>
where T: Eq,
T: Hash,
F: Fn() -> T
{
hashMap: HashMap<T, F>,
value: T,
}
我的构造函数如下所示:
pub fn new(init_value: T) -> Struct<T, F> {
Struct {
hashMap: HashMap::new(),
value: init_state,
}
}
但是,在尝试使用let a = Struct::<MyEnum>::new(MyEnum::Init);
实例化类时,编译器会抱怨泛型需要两个参数(expected 2 type arguments, found 1
)
我看到here此代码有效:
fn call_with_one<F>(some_closure: F) -> i32
where F: Fn(i32) -> i32 {
some_closure(1)
}
let answer = call_with_one(|x| x + 2);
我想问题来自于我在模板实例化中使用另一个泛型,但我该怎么做?
答案 0 :(得分:6)
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); // the closure here provides the type for `F`
}
虽然这有问题。如果我们第二次使用不同的闭包调用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));
}