Eu encontrei um comportamento de variância estranho que tenho certeza de que é uma falha na minha compreensão do sistema de tipos, mas parece um bug do compilador.
trait Trait: 'static {}
impl<T> Trait for T where T: 'static {}
struct Inner<T>(T);
fn make_inner<T: Trait>(t: T) -> Inner<Box<T>> {
Inner(Box::new(t))
}
type DynNecessary = Vec<Inner<Box<dyn Trait>>>;
struct DynCarrier {
things: DynNecessary,
}
impl DynCarrier {
pub fn spawn(&mut self, t: impl Trait + 'static) {
let inner = make_inner(t);
self.things.push(inner);
}
}
fn main() {}
No exemplo acima, make_inner
recebe T
e retorna Inner<Box<T>>
onde T é conhecido por satisfazer Trait
.
No entanto, ao tentar usar o valor de retorno de make_inner
algum lugar que aceita Inner<Box<dyn Trait>>
, obtenho o seguinte:
= note: expected struct `Inner<Box<(dyn Trait + 'static)>>`
found struct `Inner<Box<impl Trait + 'static>>`
Eu tinha um palpite de que isso tinha algo a ver com a maneira como o programa em tempo de execução trataria um dyn Trait
versus um concreto impl Trait
, mas onde isso desmorona para mim é na seguinte mudança:
fn make_inner<T: Trait>(t: T) -> Inner<Box<dyn Trait>> {
Inner(Box::new(t))
}
onde now t
é coagido com sucesso para dyn Trait
.
Que influência a inferência de tipo de retorno tem sobre tipos, que a inferência de tipo de argumento não tem? Se .push
assume a propriedade de inner
, por que não é capaz do mesmo tipo de coerção?