dart - 为什么 Dart 不能推断 List.fold() 的类型?

标签 dart flutter type-inference

我正在尝试 List.fold()在 Dart 2.1.0 中:

void main() {
  final a = [1,2,3];
  print(a.fold(0, (x,y) => x + y));
}

返回错误:

Error: The method '+' isn't defined for the class 'dart.core::Object'.

Try correcting the name to the name of an existing method, or defining a method named '+'.

它似乎无法推断出 x 的类型是 int,所以不知道如何在那里应用 + .

根据method spec , x 应该与初始值 0 具有相同的类型,这显然是一个 int为什么 Dart 不能推断出这一点?

我可以通过显式提示类型使其工作:

void main() {
  final a = [1,2,3];
  print(a.fold<int>(0, (x,y) => x + y));
}

但令我有点失望的是 Dart 无法为我推断出这一点。在大多数其他情况下,它的类型推断似乎更强。

最佳答案

Dart 类型推断按预期工作:

void main() {
  final a = [1,2,3];

  var sum = a.fold(0, (x,y) => x + y);
  print(sum);
}

它在您的示例中失败的原因是类型推断结果取决于计算表达式的上下文:

print(a.fold(0, (x,y) => x + y));

抛出错误,因为 print 参数应该是一个 Object:推断使用 Object 来填充泛型 T 键入 fold 的参数` :

T fold <T>(T initialValue, T combine(T previousValue, T element)) :

验证这个假设:

void main() {
  final a = [1,2,3];

  Object obj = a.fold(0, (x,y) => x + y);
}

抛出完全相同的错误。

带走:

类型推断效果很好,但必须注意通用表达式的周围上下文。

这是 Dart 的限制吗?

我不认为这种行为是 dart 的限制,只是一种实现选择。

可能还有一些我无法谈论的合理的理论原因,但我可以对此做出一些推理。

考虑泛型方法:

T fold <T>(T initialValue, T combine(T previousValue, T element))

及其用法:

Object obj = a.fold(0, (x,y) => x + y);

推断T类型的途径有两条:

  1. fold 返回值赋给一个Object obj0是一个Object,因为它是一个int,然后T“解析为”Object

  2. fold 第一个参数是一个int,返回值应该是一个Objectint 是一个对象, 然后 T “解析为” int

Dart 选择路径 1:它采用满足泛型方法的“最广泛”(父类(super class)型)作为推断类型。

如果 Dart 实现路径 2(推断类型是“最近”类型)应该会更好?

在这种特定情况下可能是,但随后会有不适用于路径 2 的情况。

例如,此代码段对路径 2 不满意:

abstract class Sensor {
  String getType();
}

class CADPrototype extends Sensor {
  String getType() {
    return "Virtual";
  }
}

class Accelerometer extends Sensor {
  String getType() {
    return "Real";
  }
}


T foo<T extends Sensor>(T v1, T v2, T bar(T t1, T t2)) {
  if (v2 is CADPrototype) {
    return v1;
  }
  return v2;
}

Sensor foo_what_dart_does(Sensor v1, Sensor v2, Sensor bar(Sensor t1, Sensor t2)) {
  if (v2 is CADPrototype) {
    return v1;
  }
  return v2;
}

Accelerometer foo_infer_from_argument(Accelerometer v1, Accelerometer v2, Accelerometer bar(Accelerometer t1, Accelerometer t2)) {
  if (v2 is CADPrototype) {
    return v1;
  }
  return v2;
}


void main() {
  Accelerometer v1 = Accelerometer();
  CADPrototype v2 = CADPrototype();

  Sensor result;
  result = foo(v1, v2, (p1, p2) => p1);

  // it works
  result = foo_what_dart_does(v1, v2, (p1, p2) => p1);

  // Compilation Error: CADPrototype cannot be assigned to type Accelerometer
  result = foo_infer_from_argument(v1, v2, (p1, p2) => p1);

}

关于dart - 为什么 Dart 不能推断 List.fold() 的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54379548/

相关文章:

flutter - 无法在此小部件上方找到正确的提供程序 - Flutter

flutter - 如何解决 List<dynamic> is not a subtype of type 'Map<String, dynamic>?

scala - 为什么我需要为无关输入指定类型?

haskell - 如何从类型重建 Haskell 表达式

macos - dart2js不会抛出此类文件或目录错误

flutter - flutter 中的动态芯片上出现溢出错误

flutter - 从API中的字符串中删除特殊字符

regex - TextField在whitelistingtextinputformatter中添加2个十进制正数配置后不接受输入

arrays - Julia 中的手动类型推断

dart - Flutter Navigator.of(context).pop 与 Navigator.pop(context) 区别