unsafe_ variance
Saiba mais sobre a regra de lint unsafe_variance.
Tipo inseguro: possui uma variável de tipo em uma posição não covariante.
Detalhes
#
Uma variável de instância cujo tipo contém um parâmetro de tipo da classe, mixin ou enum que a envolve, em uma posição não covariante, provavelmente causará falhas em tempo de execução devido a verificações de tipo que falham. Por exemplo, em
class C<X> {...}, uma variável de instância da forma void Function(X) myVariable;
pode causar esse tipo de falha em tempo de execução.
O mesmo vale para um getter ou método cujo tipo de retorno tem uma ocorrência não covariante de um parâmetro de tipo da declaração que o envolve.
Este lint sinaliza esse tipo de declaração de membro.
RUIM:
class C<X> {
final bool Function(X) fun; // LINT
C(this.fun);
}
void main() {
C<num> c = C<int>((i) => i.isEven);
c.fun(10); // Throws.
}
O problema é que X aparece como tipo de parâmetro no tipo de fun.
Uma forma de reduzir o risco de erros de tipo em tempo de execução é garantir que o membro não covariante
fun seja somente usado em this. Não conseguimos impor isso de forma estrita, mas podemos torná-lo privado e adicionar um método de encaminhamento
fun, de modo que possamos verificar localmente, na mesma biblioteca, que essa restrição é respeitada:
MELHOR:
class C<X> {
// ignore: unsafe_variance
final bool Function(X) _fun;
bool fun(X x) => _fun(x);
C(this._fun);
}
void main() {
C<num> c = C<int>((i) => i.isEven);
c.fun(10); // Succeeds.
}
Uma abordagem totalmente segura exige um recurso que o Dart ainda não tem, a saber, variância verificada estaticamente. Com ele, poderíamos especificar que o parâmetro de tipo
X é invariante (inout X).
É possível emular invariância sem suporte a variância verificada estaticamente. Isso impõe algumas restrições à criação de subtipos, mas fornece fielmente a tipagem que
inout daria:
BOM:
typedef Inv<X> = X Function(X);
typedef C<X> = _C<X, Inv<X>>;
class _C<X, Invariance extends Inv<X>> {
// ignore: unsafe_variance
final bool Function(X) fun; // Safe!
_C(this.fun);
}
void main() {
C<int> c = C<int>((i) => i.isEven);
c.fun(10); // Succeeds.
}
Com essa abordagem, C<int> não é subtipo de C<num>, então c
precisa ter um tipo declarado diferente.
Outra possibilidade é declarar a variável com um tipo seguro, porém mais geral. Assim, é seguro usar a própria variável, mas cada invocação precisará ser verificada em tempo de execução:
HONESTO:
class C<X> {
final bool Function(Never) fun;
C(this.fun);
}
void main() {
C<num> c = C<int>((int i) => i.isEven);
var cfun = c.fun; // Local variable, enables promotion.
if (cfun is bool Function(int)) cfun(10); // Succeeds.
if (cfun is bool Function(bool)) cfun(true); // Not called.
}
Ativar
#
Para ativar a regra unsafe_variance, adicione unsafe_variance em
linter > rules no seu arquivo analysis_options.yaml:
linter:
rules:
- unsafe_variance
Se você usa a sintaxe de mapa YAML para configurar as regras de lint,
adicione unsafe_variance: true em linter > rules:
linter:
rules:
unsafe_variance: true
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.