unsafe_variance
unsafe_type: 型変数が共変でない位置に含まれています。
詳細
#囲んでいるクラス、ミックスイン、または列挙型の型パラメーターを共変でない位置に持つインスタンス変数は、型チェックの失敗による実行時エラーの原因となる可能性があります。たとえば、class C<X> {...} では、void Function(X) myVariable; の形式のインスタンス変数は、このような実行時エラーの原因となる可能性があります。
囲んでいる宣言の型パラメーターの共変でない出現を戻り値の型に持つゲッターまたはメソッドについても同様です。
このリンターはこの種のメンバー宣言をフラグします。
悪い例
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.
}問題は、X が fun の型のパラメーター型として出現することです。
実行時型エラーの可能性を減らす 1 つの方法は、共変でないメンバー fun が のみ this で使用されることを保証することです。これを厳密に強制することはできませんが、プライベートにし、転送メソッド fun を追加することで、同じライブラリ内でこの制約が満たされていることをローカルでチェックできます。
BETTER
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.
}完全に安全なアプローチには、Dart にまだない機能、つまり静的にチェックされた共変性が必要です。それがあれば、型パラメーター X が不変 (inout X) であると指定できます。
静的にチェックされた共変性のサポートなしで不変性をエミュレートすることは可能です。これにより、サブタイプの作成にいくつかの制限が課せられますが、inout が提供する型指定を忠実に提供します。
良い例
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.
}このアプローチでは、C<int> は C<num> のサブタイプではないため、c は異なる宣言済み型を持つ必要があります。
別の可能性は、変数が安全だがより一般的な型を持つように宣言することです。その場合、変数自体を使用するのは安全ですが、すべての呼び出しは実行時にチェックする必要があります。
HONEST
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.
}有効にする
#unsafe_variance ルールを有効にするには、analysis_options.yaml ファイルの linter > rules の下に unsafe_variance を追加します。
linter:
rules:
- unsafe_variance代わりに、YAML マップ構文を使用してリンター ルールを構成している場合は、linter > rules の下に unsafe_variance: true を追加します。
linter:
rules:
unsafe_variance: true