É possível que mudar o tipo de argumento de função de impl Trait
para genérico seja uma mudança drástica? A Rust Reference afirma que:
Nota: Para parâmetros de função, parâmetros de tipo genérico e
impl Trait
não são exatamente equivalentes. Com um parâmetro genérico como<T: Trait>
, o chamador tem a opção de especificar explicitamente o argumento genérico paraT
no site da chamada usando GenericArgs , por exemplo,foo::<usize>(1)
. Seimpl Trait
for o tipo de qualquer parâmetro de função, então o chamador não pode fornecer nenhum argumento genérico ao chamar essa função. Isso inclui argumentos genéricos para o tipo de retorno ou quaisquer genéricos const.Portanto, alterar a assinatura da função de uma para outra pode constituir uma alteração drástica para os chamadores de uma função.
Mas dado que, se houver pelo menos um impl Trait
parâmetro, então o chamador não pode nomear nenhum argumento genérico, isso não deveria implicar que mudar impl Trait
para <T: Trait>
can somente permite que os chamadores nomeiem argumentos genéricos? Como os genéricos já foram inferidos, não podemos também quebrar a inferência de tipo.
EDIT: Eu presumo que cada um impl Trait
é alterado para um tipo genérico diferente e únicoimpl Trait
(sem sobreposição com outros s ou genéricos anteriores). Violar isso seria obviamente quebrar, obrigado a @啊鹿Dizzyi por apontar isso.
Listo aqui uma lista de casos (que acredito ser exaustiva) onde impl Trait
é alterado para um genérico. Se algum deles puder quebrar downstream, por favor mostre como. E se eu perdi algum caso, por favor explique se ele está quebrando.
- Mudando apenas
impl Trait
// before
pub fn foo(_: impl Trait) {}
// after
pub fn foo<T: Trait>(_: T) {}
- Muitos
impl Trait
, mas mudando apenas alguns deles
// before
pub fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}
// after
pub fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
- Muitos
impl Trait
, mudando todos eles
// before
pub fn foo(_: impl Trait1, _: impl Trait2, _: impl Trait3) {}
// after
pub fn foo<T1: Trait1, T2: Trait2, T3: Trait3>(_: T1, _: T2, _: T3) {}
- Alguns tipos genéricos, alterando alguns
impl Trait
s, mas deixando pelo menos um
// before
pub fn foo<T1: Trait1>(_: T1, _: impl Trait2, _: impl Trait3) {}
// after
pub fn foo<T1: Trait1, T2: Trait2>(_: T1, _: T2, _: impl Trait3) {}
- Alguns tipos genéricos, alterando todos os
impl Trait
s
// before
pub fn foo<T1: Trait1>(_: T1, _: impl Trait2, _: impl Trait3) {}
// after
pub fn foo<T1: Trait1, T2: Trait2, T3: Trait3>(_: T1, _: T2, _: T3) {}
Um dos casos em que isso acontece é quando você quer que a função receba dois argumentos que implementam alguma característica,
Trait
mas você não se importa se dois dos argumentos são do mesmo tipo ou não.Já que quando você define um tipo genérico
T
, todas as aparências são vinculadas a esse mesmo tipo. E causará erro, portanto, você precisará ter cuidado ao alterar.Exemplo
Mensagem de erro
Recentemente editei esta parte da referência, pois estava desatualizada. Você pode ver a atualização na versão noturna (deve atingir a estabilidade amanhã, 5 de setembro).
Resumindo, 1.63.0 adicionou a possibilidade de especificar genéricos quando
impl Trait
presente. Até onde eu sei, você está certo de que não poderia ser uma mudança de quebra. Desde 1.63.0, pode ser uma mudança de quebra se houver pelo menos um genérico existente.A versão longa está em PR #1495 .