请考虑下面的代码:

mixin M {}

abstract class I {}

class A = I with M;

class B = I with M;

void main() {
  final A? a = A();
  final B? b = B();

  final I? i1 = a ?? b; // compilation error saying "A value of type 'Object?' can't be assigned to a variable of type 'I?'"
}

您能帮我解释一下为什么我在使用"?"时会出现编译错误吗?接线员.

DART 2.19.0

推荐答案

a ?? b表达式需要找出表示两个可能的结果值的单个类型,一个是类型A,另一个是类型B?.

它不判断AB?是否都可以赋值给I?,而是try 找出a ?? b结果的类型,作为组合了AB?的单个类型,这意味着同时找到AB的超类型.

为此,它使用语言指定的"最小上界"算法计算上界.(我引用这个名字,因为它找到了an的上限,这有时是最小的上限,但并不总是.)

这两种类型是:

  • A和直接超类型IM,这两个类型都具有立即超类型Object,它具有超类型Object?(和所有其他顶级类型).
  • B?具有超型I?M?及其超型Object?.

这里的问题是,虽然它可以看到II?出现在这些类型中,因此它可以确定I?是上限, 它还找到MM?并确定M?是上界, 而这两种类型在其他方面是完全等价的,它们具有相同长度的超级链,最高可达Object,并且彼此不相关.least的上限也不是.因此,该算法忽略它们,并寻找既共享又没有另一种相同类型的"深度从Object开始"的内容.它找到了Object?个. 它不能赋值给I.

这是DART中最小上界算法的一个已知缺点(在几个中),但这是一个很难以最佳方式解决的问题,因为对于一个类来说,引入一些内部私有超类非常容易,有时会引入两个公共子类的类型then becomes the least upper bound,这让用户摸不着头脑.

requests个可以做得更好,例如,通过不忽略上下文类型,但更改类型推断必须非常小心地完成.它可以 destruct 已针对当前行为进行微调的现有代码.

这里没有很好的变通方法,但有一些实用的变通方法.

您必须重写代码以确保两个分支的静态类型中都不包含不必要的M类型. 我没有将结果向下强制转换为I?(这需要运行时类型判断),而是向上强制转换原始值:

final I? i3 = a ?? (b as I?); // ignore: unnecessary_cast

这应该是完全自由的向上投射,但可能(将!)导致分析器警告,您将不得不忽略.

Dart相关问答推荐

禁用 ListView 滚动

Dart:使用正则表达式从字符串中删除空格

在构建函数之外使用 BuildContext

如何使用 Android aar 文件构建 Flutter 项目?

如何从 Flutter App 连接 Ms SQL?

Dart 捕获 http 异常

在 Dart 中将对象推入数组

'Future' 的实例而不是显示值

在 Flutter 中推送新页面时,Navigator 堆栈上的页面会重建

Flutter-当文本字段有焦点时隐藏提示文本

向 javascript 公开 Dart 函数

在 Dart 中编写单元测试的最佳方式是什么?

Dart:异步抽象方法

如何从 Dart 中的字符串中删除换行符?

如何在 Dart 中从外部查询 shadow DOM 中的元素?

如何在dart中生成随机字符串?

Dart 中的 Math.round() 在哪里?

如何在 Dart 中定义接口?

dart列表最小值/最大值

如何在 Dart 中创建私有变量?