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

Dart运行时类型错误:'(int) => void' 非 '(Object) => void' 子类型

为什么int是Object子类却出现函数类型不匹配的运行时错误?

先给你拆解核心原因:这是Dart的函数参数逆变性和泛型类默认不变性共同导致的,跟你想的“子类就能兼容”不是一回事。

核心问题1:函数参数是逆变的,不是协变的

你以为(int)=>void能当(Object)=>void用?恰恰相反。Dart里函数参数的类型兼容性是逆变的——如果Sub是Super的子类,那Function(Super)是Function(Sub)的子类型,反过来不行。

放到你的代码里:

  • 你创建的DropdownField<int>里,setValue是(int)=>void,只能接受int类型的参数;
  • 但你把它当作DropdownField<Object>处理时,程序期望的setValue是(Object)=>void,得能接受任何Object子类(比如String、bool)。
    如果允许把(int)=>void赋值给(Object)=>void,那万一有人传个String进去,你的函数直接就崩了。所以Dart在运行时会拦截这种不安全的类型转换,抛出你看到的错误。

核心问题2:泛型类默认是不变的

DropdownField<V>这种泛型类,默认是不变的——哪怕int是Object的子类,DropdownField<int>也不是DropdownField<Object>的子类型。

你代码里的if (field is DropdownField<Object>)理论上不该匹配DropdownField<int>实例,但大概率你实际写的时候是省略了泛型参数(比如写成field is DropdownField),Dart会允许你把它强转成DropdownField<Object>,这就埋下了不安全的隐患,直接导致后续调用_buildDropdownField时触发类型错误。

修复方案

方案1:给泛型参数加协变标记

修改DropdownField的泛型参数为covariant V,这样DropdownField<int>就能被当作DropdownField<Object>处理:

class DropdownField<covariant V> extends ModelField {
  final void Function(V value) setValue;
  final List<V> options;

  DropdownField({
    required this.setValue,
    required this.options,
  });
}

⚠️ 注意:协变会降低类型安全性,要是后续有人给setValue传个非int的Object类型参数,还是会崩,所以只在你能确保不会出现这种情况时用。

方案2:用泛型类型变量安全处理

在_renderField里通过泛型类型变量捕获实际类型,避免不安全的强转:

void _renderField(ModelField field) {
  if (field is DropdownField) {
    _buildDropdownField(field as DropdownField<dynamic>);
  }
}

用dynamic绕开编译时检查,但会丢失部分类型安全,适合快速修复。

方案3:Dart3.0+用模式匹配

如果你的项目用Dart3.0及以上,可以用模式匹配直接处理,不用显式转型:

void _renderField(ModelField field) {
  if (field case DropdownField(:final options)) {
    if (options.isNotEmpty) {
      field.setValue(options.first);
    }
  }
}

让Dart自动处理类型推断,既安全又简洁。

总结

你碰到的问题不是继承关系的问题,是Dart为了类型安全设计的函数逆变和泛型不变性导致的。选哪种修复方式,看你对类型安全性的要求和业务场景。

内容的提问来源于stack exchange,提问作者TSR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:10:56