Dart带泛型的父类赋值出现类型错误,无需显式cast怎么解决?
报错原因
这个问题的核心是Dart的三元表达式类型推断规则:三元表达式会取两个分支值的最小公共上界类型作为整个表达式的最终类型。
- 无泛型的场景下,B和C的最小公共上界就是A,所以三元表达式返回值类型为A,可以直接赋值给类型为A的变量,没有问题。
- 带泛型的场景下,B是
A<int>的子类,C是A<String>的子类,Dart的泛型默认是协变的,此时A<int>和A<String>的最小公共上界并不是你预期的A<dynamic>,而是顶层类型Object。同时你写的final A a会被Dart自动补全为final A<dynamic> a,把Object类型的值赋值给A<dynamic>类型的变量自然会触发类型不匹配的报错。
无显式as的实现方案
有两种常用的实现方式,完全不需要显式加as A做强制转换:
方案1:抽取非泛型父类/接口
如果你的统一操作只涉及A的非泛型成员,最安全的方式是单独抽一层非泛型的父类或者接口,所有泛型A都继承自这个非泛型基类:
abstract class ABase {} class A<T> extends ABase {} class B extends A<int> {} class C extends A<String> {} var b = true; final ABase a = b ? C() : B();
此时三元表达式两个分支的最小公共上界就是ABase,可以直接赋值,没有任何类型安全风险。
方案2:通过函数返回值指定类型
你可以把生成实例的逻辑封装成返回值为A(即A<dynamic>)的函数,Dart会自动对返回值做类型适配,不需要手动强制转换:
class A<T> {} class B extends A<int> {} class C extends A<String> {} A createA(bool b) => b ? C() : B(); var b = true; final A a = createA();
这种方式可以直接复用你现有的类结构,不需要修改类的继承关系。
内容的提问来源于stack exchange,提问作者Valentin Vignal
相关产品推荐
相关产品推荐

