为什么 Dart 不能推断 List.fold() 的类型?
Why can't Dart infer the type of List.fold()?
我正在尝试 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
填充 fold 的通用 T
类型参数:
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
的类型有两种途径:
fold
返回值赋给一个 Object obj
,0
是一个 Object
因为它是一个 int
,然后T
"resolve to" Object
fold
第一个参数是一个 int
,返回值应该是一个 Object
而 int
是一个 Object
,
然后 T
"resolve to" int
Dart 选择路径 1:它采用满足泛型方法的 "broadest"(超类型)作为推断类型。
如果Dart实现路径2(推断类型为"nearest"类型)应该会更好?
在这种特定情况下可能是,但随后会有不适用于路径 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);
}
我正在尝试 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
填充 fold 的通用 T
类型参数:
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
的类型有两种途径:
fold
返回值赋给一个Object obj
,0
是一个Object
因为它是一个int
,然后T
"resolve to"Object
fold
第一个参数是一个int
,返回值应该是一个Object
而int
是一个Object
, 然后T
"resolve to"int
Dart 选择路径 1:它采用满足泛型方法的 "broadest"(超类型)作为推断类型。
如果Dart实现路径2(推断类型为"nearest"类型)应该会更好?
在这种特定情况下可能是,但随后会有不适用于路径 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);
}