我有以下 Rust 玩具代码,它正在构建一个带有闭包的全局 HashMap,该闭包返回一个正在实现 Trait 的 Struct(请原谅这个愚蠢的示例)
struct Cow {
}
struct Sheep {
}
pub trait Animal {
fn make_sound(&self) -> ();
}
impl Animal for Cow {
fn make_sound(&self) -> () {
println!("mooo!");
}
}
impl Animal for Sheep {
fn make_sound(&self) -> () {
println!("baaa!");
}
}
fn make_cow() -> Cow {
return Cow{};
}
fn make_sheep() -> Sheep {
return Sheep{}
}
/*lazy_static! {
static ref ANIMALKINGDOM1:HashMap<String,fn()->Box<dyn Animal>> = HashMap::from([
(String::from("cow"),make_cow),
(String::from("sheep"),make_sheep)
]);
}*/
/*lazy_static! {
static ref ANIMALKINGDOM2:HashMap<String,fn()->Box<dyn Animal>> = HashMap::from([
(String::from("cow"),|| Box::new(make_cow())),
(String::from("sheep"),|| Box::new(make_sheep()))
]);
}*/
static CowBoxingClosure: fn() -> Box<dyn Animal> = || Box::new(make_cow());
lazy_static! {
static ref ANIMALKINGDOM3:HashMap<String,fn()->Box<dyn Animal>> = HashMap::from([
(String::from("cow"),CowBoxingClosure),
(String::from("sheep"),|| Box::new(make_sheep()))
]);
}
现在,我明白我不能使用 ANIMALKINGDOM1 案例,因为 make_sheep 和 make_cow 返回 Cow 和 Sheep。
为了解决这个问题,我尝试使用闭包(ANIMALKINGDOM2),它只是将 make_sheep 和 make_cow 的返回值装箱以获取 dyn Animal。但编译器抱怨说,虽然两个闭包具有相同的类型,但它们并不相同,并建议对闭包进行装箱。
那么为什么编译器在 ANIMALKINGDOM3 的情况下不会抱怨呢?
这将创建一个数组。编译器假定数组元素类型是第一个元素的类型。
第一个元素的类型是
(String, <Closure: || Box::new(make_cow())>)
。但是,由于没有两个闭包具有相同的类型,因此第二个闭包的类型与(String, <Closure: || Box::new(make_sheep())>)
第一个元素的类型不匹配。编译器不够智能,无法将
HashMap
through的类型反向传播HashMap::from
到数组中,因此无法将闭包强制转换为函数指针fn() -> Box<dyn Animal>
。但是在第三个示例中,您
CowBoxingClosure
在声明静态时使用了预先强制转换为函数指针的函数。这使得数组元素类型(String, fn() -> Box<dyn Animal>)
和第二个元素按预期被强制。实现您想要的效果的另一种方法是显式告诉编译器将闭包强制转换为函数指针: