You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart泛型报错:List<(String?) => String?>不是List<(dynamic) => String?>子类型

报错原因

该报错是Dart的函数参数逆变规则、集合泛型不变特性共同导致的:
你将具体泛型类型的MyFormControl实例赋值给声明为MyFormControl<dynamic, dynamic>的变量时,内部的List<FormFieldValidator<ViewT>>不会自动转换为List<FormFieldValidator<dynamic>>。
FormFieldValidator<T>是接收T?类型参数的函数,函数参数类型属于逆变:FormFieldValidator<String>只能接收String?类型的入参,而FormFieldValidator<dynamic>可以接收任意类型入参,因此前者不是后者的子类型。同时Dart的List属于不变类型,只要泛型参数不匹配,整个List类型就完全不兼容,哪怕你只是读取属性不做修改,访问时也会触发运行时类型校验抛出错误。

Dart泛型与dynamic运行时核心规则
  • 函数参数类型为逆变:如果类型A是B的子类,那么Function(B)是Function(A)的子类型,反过来不成立。本问题中String是dynamic的子类,因此(dynamic)=>String?是(String?)=>String?的子类型,后者无法赋值给前者。
  • 集合类型(List/Map/Set等)为不变:List<X>仅和完全同类型的List<X>兼容,不存在父子类继承关系,哪怕X和Y有父子类关系也不兼容。
  • dynamic仅在编译期跳过类型检查,运行时会严格校验实际类型是否和声明类型匹配,不匹配就抛出类型错误。
解决方案

方案1(最推荐,符合封装原则)

将验证逻辑封装在MyFormControl内部,外部不需要访问泛型属性validators,完全规避类型不匹配问题:

class MyFormControl<ViewT, DataT> {
  final ViewT? value;
  final List<FormFieldValidator<ViewT>> validators;
  final List<Future<FormFieldValidator<ViewT>>> asyncValidators;
  final MyFormConverter<ViewT, DataT>? converter;

  MyFormControl({
    this.value,
    this.validators = const [],
    this.asyncValidators = const [],
    this.converter,
  });

  // 新增内部验证方法,泛型逻辑完全封闭在类内部
  String? validate() {
    for (var validator in validators) {
      final error = validator(value);
      if (error != null) return error;
    }
    return null;
  }
}

// MyForm部分直接调用封装好的验证方法
abstract class MyForm {
  final Map<String, MyFormControl<dynamic, dynamic>> form;
  final Map<String, String> errors = <String, String>{};
  final List<FormFieldValidator<dynamic>> formValidators;
  MyForm(this.form, {this.formValidators = const []});

  bool validate() {
    bool valid = true;
    form.forEach((key, control) {
      final errorText = control.validate();
      if (errorText != null) {
        errors.putIfAbsent(key, () => errorText);
        valid = false;
      }
    });
    return valid;
  }
}

方案2(类型擦除适配)

如果不想修改MyFormControl的结构,可以在访问validators时做类型擦除,手动适配泛型:

abstract class MyForm {
  final Map<String, MyFormControl<dynamic, dynamic>> form;
  final Map<String, String> errors = <String, String>{};
  final List<FormFieldValidator<dynamic>> formValidators;
  MyForm(this.form, {this.formValidators = const []});

  bool validate() {
    bool valid = true;
    form.forEach((key, control) {
      // 先转成无泛型的Function列表,跳过泛型校验
      for (var validator in control.validators as List<Function>) {
        // 入参是control自身的value,和validator的参数类型天然匹配,不会运行时报错
        final errorText = validator(control.value) as String?;
        if (errorText != null) {
          errors.putIfAbsent(key, () => errorText);
          valid = false;
          break;
        }
      }
    });
    return valid;
  }
}

内容的提问来源于stack exchange,提问作者Edgars Beļevičs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:27:01