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
相关产品推荐
相关产品推荐

