unsafe_variance
不安全型別:在非協變位置包含型別變數。
詳細資訊
#一個例項變數,如果其型別在非協變位置包含其所在類、混入或列舉的型別引數,則很可能由於型別檢查失敗而導致執行時錯誤。例如,在 class C<X> {...} 中,形式為 void Function(X) myVariable; 的例項變數可能會導致此類執行時錯誤。
對於返回型別在其所在宣告的型別引數中存在非協變位置的 getter 或方法,情況也是如此。
此 lint 規則會標記此類成員宣告。
不良示例
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 的型別中作為引數型別出現。
減少執行時型別錯誤潛力的一種方法是確保非協變成員 fun 僅在 this 上使用。我們無法嚴格強制執行此操作,但可以將其設為私有,並新增一個轉發方法 fun,以便可以在同一庫中本地檢查此約束是否得到滿足。
更好示例
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 尚未具備的一個特性,即靜態檢查的方差 (variance)。有了它,我們可以指定型別引數 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 必須具有不同的宣告型別。
另一種可能性是將變數宣告為一個安全但更通用的型別。這樣使用變數本身是安全的,但每次呼叫都必須在執行時進行檢查。
誠實示例
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 規則,請在 linter > rules 下新增 unsafe_variance: true
linter:
rules:
unsafe_variance: true