下面是一些我觉得很有趣的dart 代码:

void main() {
  A<num> someA = B();
  A value = switch (someA) {
      B() => B(),
      C() => C(),
  };
}

sealed class A<T extends num> {}
final class B extends A<int> {}
final class C extends A<double> {}

如果您try 编译此代码,则会得到有关Switch语句的错误:A value of type 'Object' can't be assigned to a variable of type 'A<num>'. Try changing the type of the variable, or casting the right-hand type to 'A<num>'.

我的问题是,为什么编译器不能推断出这两者之间的公共父类型呢?(我猜是这样的……默认设置为Object.)如果您编写了类似var myThing = true ? 1.5 : 7;的代码,DART会推断myThing的预期类型为num.为什么它不在这里这样做呢?

当然,当你这样做的时候,这一切都是固定的

void main() {
  A<num> someA = B();
  A value = switch (someA) {
      B() => B() as A,
      C() => C() as A,
  };
}

sealed class A<T extends num> {}
final class B extends A<int> {}
final class C extends A<double> {}

取而代之的是.另外,值得注意的是,当类型参数<T extends num>不存在时,不会出现这个问题--所以泛型类型的某些方面阻止了编译器推断预期的类型(或者至少是我预期的类型).

编辑:switch个表达式的行为和列表表达式之间有一个有趣的区别(如果你将它们结合在一起):

void main() {
  // `values_var` is `List<Object>`
  var values_var            = [B(), C()];
  List<A> values_List1      = [B(), C()];
  List<A<num>> values_List2 = [B(), C()];
  // all of the above compiles fine

  A<num> someA = B();
  
  // does not compile
  A value = switch (someA) {
      B() => B(),
      C() => C(),
  };

  // DOES compile
  List<A> value = switch (someA) {
      B() => [B()],
      C() => [C()],
  };
}

这是我最初问题的一个更清晰的版本:为什么类型推断像我期望的那样对列表起作用,而对switch个表达式(没有列表)却不起作用?

推荐答案

我的问题是,为什么编译器不能推断出两者之间的公共父类型?

这是由于DART用于类型推理的最小上限算法.

您可以在语言规范中阅读有关最小上限的信息:

https://spec.dart.dev/DartLangSpecDraft.pdf#Least%20Upper%20Bounds

在GitHub上的DART语言库中,有许多与最小上界相关的开放问题,不是推断所需的类型(而是推断过于通用的类型,通常是Object):

https://github.com/dart-lang/language/labels/least-upper-bound

似乎正在追踪这个问题的主要问题可以在这里找到:

https://github.com/dart-lang/language/issues/1618

我自己也在不久前打开了一个与此相关的问题,那里的回复也很有见地:

https://github.com/dart-lang/language/issues/2953


如果您写了类似var myThing = true ? 1.5 : 7;的内容,DART会推断出myThing的预期类型为num.为什么它不在这里这样做呢?

我的理解是,最小上限只有在涉及泛型时才起作用.

没有泛型的相同类层次 struct 不会产生任何错误.

void main() {
  A someA = B();
  A value = switch (someA) {
      B() => B(),
      C() => C(),
  };
}

sealed class A {}
final class B extends A {}
final class C extends A {}

为什么类型推断像我预期的那样适用于列表,而不适用于switch个表达式(没有列表)?

我不是list literal inference%确定这一点,但我最好的猜测是,如果您阅读语言规范中关于list literal inference的部分,它提到在确定类型时列表文字将上下文类型考虑在内.

如果你通读上面链接的GitHub问题,似乎当前围绕最小上限的问题发生在没有考虑上下文类型的情况下.

Dart相关问答推荐

空值判断运算符 - Flutter

Flutter - 对 Cloud Firestore 进行排序

如何在Flutter中制作视频缩略图?

GPS是否激活

如何防止意外发布私有 pub 包

在 Dart 中,List.unmodifiable() 和 UnmodifiableListView 有什么不同?

如何根据用户在Flitter中的时间显示问候,如早上好、下午好或晚上好

Dart VM 的性能与 Node.js 相比如何?

IndexedDB访问速度和效率

如何突出显示所选卡片的边框?

Dart 有小部件库吗?

找到两个数字中larger/smaller的方法是什么

Dart Nodejs 和 Socketio

用默认值初始化成员的最优雅的方法

dart:io 中带有 json 内容类型的 Http POST 请求

Dart - 如何对 Map 的键进行排序

_internal 的语义是什么?

Dart 中不同的 Map 实现有什么区别?

将`_`(即下划线)作为唯一参数传递给 Dart 语言函数是什么意思?

如何用 Dart 格式化日期?