跳到主要內容

unsafe_variance

實驗性

不安全的型變:在非共變位置中有型別變數。

詳細資訊

#

類型在非共變位置包含封閉類別、Mixin 或列舉的類型參數的實例變數,很可能因為類型檢查失敗而導致執行階段錯誤。例如,在 class C<X> {...} 中,void Function(X) myVariable; 形式的實例變數可能會導致此類執行階段錯誤。

對於回傳類型在封閉宣告的類型參數中具有非共變出現的 getter 或方法來說,情況也是如此。

此 Linter 標記此類成員宣告。

不良範例

dart
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,以便我們可以在同一個程式庫中在本機檢查是否滿足此約束。

較佳範例

dart
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 會給出的類型。

良好範例

dart
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 必須具有不同的宣告類型。

另一種可能性是宣告變數具有安全但更通用的類型。然後可以安全地使用變數本身,但每次調用都必須在執行階段檢查。

誠實範例

dart
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

analysis_options.yaml
yaml
linter:
  rules:
    - unsafe_variance

如果您改為使用 YAML 地圖語法來配置 Linter 規則,請在 linter > rules 下新增 unsafe_variance: true

analysis_options.yaml
yaml
linter:
  rules:
    unsafe_variance: true