Eu tenho o seguinte código de brinquedo Rust, que está construindo um HashMap global com fechamentos que retornam um Struct que está implementando um Trait (desculpe o exemplo bobo)
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()))
]);
}
Agora, entendo que não posso usar o caso ANIMALKINGDOM1 porque make_sheep e make_cow retornam Cow e Sheep.
Para resolver isso tentei usar encerramentos (ANIMALKINGDOM2) que apenas encaixotam o valor retornado de make_sheep e make_cow para obter dyn Animal. Mas o compilador reclama que embora dois encerramentos tenham o mesmo tipo, eles não são iguais e está sugerindo encaixotar os encerramentos.
Por que então o compilador não reclama no caso do ANIMALKINGDOM3?
Isso cria uma matriz. O compilador assume que o tipo de elemento da matriz é o tipo do primeiro elemento.
O tipo do primeiro elemento é
(String, <Closure: || Box::new(make_cow())>)
. No entanto, como não existem dois encerramentos do mesmo tipo, o tipo do segundo encerramento é(String, <Closure: || Box::new(make_sheep())>)
aquele que não corresponde ao tipo do primeiro elemento.O compilador não é inteligente o suficiente para propagar retroativamente o tipo de
HashMap
throughHashMap::from
no array e, portanto, é incapaz de forçar os fechamentos em ponteiros de funçãofn() -> Box<dyn Animal>
.Mas com seu terceiro exemplo, você usa
CowBoxingClosure
which é pré-coagido em um ponteiro de função ao declarar o estático. Isso faz com que o tipo de elemento da matriz(String, fn() -> Box<dyn Animal>)
e o segundo elemento sejam forçados conforme o esperado.Outra maneira de conseguir o que você deseja é dizer explicitamente ao compilador para forçar os fechamentos em ponteiros de função: