class A<T> {
final T data;
final T Function(T) convert;
A(this.convert, this.data);
Type get genericType => T;
}
void main(List<String> args) {
final list = <A>[
A<int>((i) => i + i, 0),
A<String>((i) => i + i, '0'),
];
print(list[0].data); // ok
print(list[0].convert); // runtime error: type '(int) => int' is not a subtype of type '(dynamic) => dynamic'
}
看起来dart认为函数类型不兼容。但是为什么这会发生在运行时,我应该如何解决它而不失去编译时类型检查的优势。
编辑:
我发现如果我在阅读这个函数之前向上转换元素,就可以了:
final first = list[0] as A<int>;
print(first.convert); // ok
所以我想找到一种在运行时动态上抛元素的方法,我添加了一个方法,根据其他stackoverflow的答案来获取类A的实际泛型类型。
Type get genericType => T;
如果我能做到这一点就太好了:
final t = list[0].genericType;
final first = list[0] as A<t>;
print(first.convert);
不幸的是我不能。作为一个肮脏的变通方案,如果我有一个有限的泛型数量,我可以这样做:
final t = list[0].genericType;
if (t == int) {
final first = list[0] as A<int>;
print(first.convert);
} else if (t == String) {
final first = list[0] as A<String>;
print(first.convert);
}
2条答案
按热度按时间wydwbb8l1#
发生这种情况是因为列表被声明为
List<A>
类型,它等价于List<A<dynamic>>
,这导致编译器对dynamic
进行类型检查。在运行时,第二个表达式成为了一个问题。对象实际上是
(int) => int
类型,强制int
输入到函数中,而不是接受编译器所期望的dynamic
的任何子类型。编译器的想法和运行时的说法之间的矛盾导致抛出异常。不幸的是,除了重写整个构造之外,没有真实的的方法来解决这个问题。Dart是围绕着类型推理机制的,当你将列表转换为
A<dynamic>
时,编译器会丢失很多信息。j0pj023g2#
声明
A<int>
convert
变为int Function (int)
;声明A<String>
转换为String Function (String)
;由于jraufeisen Dart的答案中的原因,请将convert
方法的T
参数视为dynamic
,并告知您参数类型不匹配(我个人同意您的编程方法,我希望在Dart未来版本的直接强制转换中可以解决此问题)。不过,要解决您的问题,您只需执行以下操作:
将转换声明为:
或在A上不做任何更改,将参数类型转换为动态: