考虑以下代码:
void printInt(int i) => print(i);
void printString(String s) => print(s);
void printSomething(Object o) {
final printer = {
int: printInt,
String: printString,
}[o.runtimeType];
print('Printer is $printer');
printer(o);
}
void main() => printSomething('Hello');
它会打印正确的printString
函数,然后崩溃,但出现以下异常:
TypeError: "Hello": type 'String' is not a subtype of type 'Null'
为什么会这样?
答案 0 :(得分:2)
该错误来自以下事实:您的地图已被赋予类型Map<Type, void Function(Null)>
,因为这是它可以基于列表内容使用的唯一类型。
问题在于Dart无法为您的地图提供其他类型,因为从类型系统的角度来看,其他任何事情都是无效的。假设类型为Map<Type, void Function(Object)>
。好吧,然后我们可以从该映射中将任何对象发送到方法中。但这是不允许的,因为映射中的两个方法明确定义为接受int
和String
而不是Object
。
因为我们有一个采用Map<Type, void Function(int)>
的方法,所以我们可以给它指定类型String
。
此外,Map<Type, void Function(dynamic)>
与Object
的问题相同,因为两种方法都明确定义为采用精确类型。
所以Dart会改用Null
作为参数的类型,因为我们知道对这两种方法有效的唯一方法就是null
值。
由于您然后尝试将String
作为参数提供给签名为void Function(Null)
的方法,因此从类型系统中会收到错误消息。
如果您想运行代码,则需要告诉类型系统充分了解您的工作。为此,对于从地图上接收的方法类型,应使用dynamic
:
void printInt(int i) => print(i);
void printString(String s) => print(s);
void printSomething(Object o) {
final dynamic printer = {
int: printInt,
String: printString,
}[o.runtimeType];
print('Printer is $printer');
printer(o);
}
void main() => printSomething('Hello');