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

Dart泛型类类型异常:'(SpecificType)=>String'非'(dynamic)=>String'子类型

问题描述

编写Flutter模块化包的泛型Dart类时出现运行时类型异常,代码可正常编译,但执行时崩溃,错误信息为:

type '(Dog) => String' is not a subtype of type '(dynamic) => String'

复现代码如下:

void main() {
  var sc = Shelter<Cat>(
    name: 'test shelter', 
    data: [Cat(id: 'cat-1', name: 'cat no.1')],
    extractParam: (data) => data.id,
  );

  var sd = Shelter<Dog>(
    name: 'test shelter dog', 
    data: [Dog(dogId: 'dog-1', name: 'dog no.1')],
    extractParam: (data) => data.dogId,
  );

  print(sc.extractParam(Cat(id: 'cat-2', name: 'cat no.2')));
  print(sd.extractParam(Dog(dogId: 'dog-2', name: 'dog no.2')));

  var dog = Dog(dogId: 'dog-3', name: 'dog no.3');
  var test = Test(
    data: dog,
    shelter: sd,
  );
  test.printTest();

  print("hello before testtest()");
  for (var c in sc.data) {
    final d = sc.extractParam(c);
    print(d);
  }
  testtest(sd);
}

void testtest(Shelter shelter) {
  for (var a in shelter.data) {
    final b = shelter.extractParam(a);
    print(b);
  }
}

class Test<T> {
  final T data;
  final Shelter<T> shelter;

  const Test({
    required this.data,
    required this.shelter,
  });

  void printTest() => print('This is test: ${shelter.extractParam(data)}');
}

class Dog {
  final String dogId;
  final String name;

  const Dog({
    required this.dogId,
    required this.name,
  });
}

class Cat {
  final String id;
  final String name;

  const Cat({
    required this.id,
    required this.name,
  });
}

class Shelter<T> {
  final String name;
  final List<T> data;
  final String Function(T data) extractParam;

  const Shelter({
    required this.name,
    required this.data,
    required this.extractParam,
  });
}

运行日志:

➜  test_dart dart ./bin/test_generic_field_extract.dart
cat-2
dog-2
This is test: dog-3
hello before testtest()
cat-1
Unhandled exception:
type '(Dog) => String' is not a subtype of type '(dynamic) => String'
#0      testtest (file:///Users/tharineemunkwamdee/projects/test_dart/bin/test_generic_field_extract.dart:34:23)
#1      main (file:///Users/tharineemunkwamdee/projects/test_dart/bin/test_generic_field_extract.dart:29:3)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:296:19)
#3      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
➜  test_dart 
错误原因

问题根源在testtest函数的参数定义:void testtest(Shelter shelter)省略了泛型参数,导致Dart将shelter推断为Shelter<dynamic>类型。

Shelter<T>中的extractParam是String Function(T)类型,当传入的是Shelter<Dog>时,extractParam实际是(Dog)=>String。但当shelter被当作Shelter<dynamic>处理时,Dart期望extractParam是(dynamic)=>String——由于(Dog)=>String只能接受Dog类型参数,无法兼容dynamic类型,因此触发类型不匹配的运行时异常。

解决方法

给testtest函数添加泛型参数,让它支持任意类型的Shelter<T>,确保类型一致:

  • 修改函数定义为void testtest<T>(Shelter<T> shelter)
  • 遍历shelter.data时,每个元素类型为T,可直接被extractParam正确接收
修改后的完整代码
void main() {
  var sc = Shelter<Cat>(
    name: 'test shelter', 
    data: [Cat(id: 'cat-1', name: 'cat no.1')],
    extractParam: (data) => data.id,
  );

  var sd = Shelter<Dog>(
    name: 'test shelter dog', 
    data: [Dog(dogId: 'dog-1', name: 'dog no.1')],
    extractParam: (data) => data.dogId,
  );

  print(sc.extractParam(Cat(id: 'cat-2', name: 'cat no.2')));
  print(sd.extractParam(Dog(dogId: 'dog-2', name: 'dog no.2')));

  var dog = Dog(dogId: 'dog-3', name: 'dog no.3');
  var test = Test(
    data: dog,
    shelter: sd,
  );
  test.printTest();

  print("hello before testtest()");
  for (var c in sc.data) {
    final d = sc.extractParam(c);
    print(d);
  }
  testtest(sd);
}

// 添加泛型参数T,确保类型匹配
void testtest<T>(Shelter<T> shelter) {
  for (var a in shelter.data) {
    final b = shelter.extractParam(a);
    print(b);
  }
}

class Test<T> {
  final T data;
  final Shelter<T> shelter;

  const Test({
    required this.data,
    required this.shelter,
  });

  void printTest() => print('This is test: ${shelter.extractParam(data)}');
}

class Dog {
  final String dogId;
  final String name;

  const Dog({
    required this.dogId,
    required this.name,
  });
}

class Cat {
  final String id;
  final String name;

  const Cat({
    required this.id,
    required this.name,
  });
}

class Shelter<T> {
  final String name;
  final List<T> data;
  final String Function(T data) extractParam;

  const Shelter({
    required this.name,
    required this.data,
    required this.extractParam,
  });
}
运行结果

修改后执行代码,可正常输出所有结果,无异常:

cat-2
dog-2
This is test: dog-3
hello before testtest()
cat-1
dog-1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:43:13