你好,当我使用这个通用方法时,我得到这个错误
<块引用>“num”类型的值不能分配给“T”类型的变量。尝试更改变量的类型,或将右侧类型转换为“T”。
这里的错误是什么
sums<T extends num>(List<T> list) {
T res =list[0];
for (var i = 1; i < list.length; i++) {
res = res + list[i];
}
print(res);
}
答案 0 :(得分:2)
这里的问题是 Dart 2.12.0 中引入的新 Null Safety 功能从语言中删除了隐式向下转换。
如果 res
的类型为 T
where T extends num
,则操作 res + something
具有静态类型 num。我们对 T
的唯一了解是它实现了 num
,而 num.operator+
返回 num
。
但是,num
不能分配给 T extends num
,因为后者是前者的子类型(T
可能是 int
,并非所有 num
值都可以分配给int
)。
所以,你需要一个显式转换来使赋值有效:
res = (res + list[i]) as T;
就是这样的演员。如果你只写 res = res + list[i] as T;
,那么 as
的优先级意味着它与上面的强制转换相同。
在 Dart 2.10.x 中,它无需显式转换即可工作,因为该语言为您插入了 隐式 转换。
如果你写 res += list[i] as T;
则表示 res = res + (list[i] as T);
这是一个不必要的转换,因为 list[i]
已经有类型 T
,并且不会转换加法的结果。
对于 int res = ...; res = res + otherInt;
而言,这不会一直失败的原因是语言规范特别对待 int.operator+
(以及一些类似的整数运算符)并识别结果何时为整数,即使+
运算符的返回类型是 num
。这种特殊情况不适用于 T extends num
。
答案 1 :(得分:1)
这似乎是 Dart 2.12+ 的错误或被误解的功能。无论哪种情况,都值得在 Dart Github 页面上提出问题。
如果我在 2.12.0 中运行以下代码:
void main() {
final nums = [1, 2.0, 3.5];
final ints = [1, 2, 3];
final doubles = [1.1, 2.2, 3.3];
sums(nums);
sums(ints);
sums(doubles);
}
void sums<T extends num>(List<T> list) {
T res = list[0];
for (var i = 1; i < list.length; i++) {
res = res + list[i];
}
print(res);
}
我收到您提到的错误:
main.dart:14:9: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
res = res + list[i];
^
但是,如果我在 Dart 2.10.5 中运行相同的代码,则该程序可以毫无问题地编译和运行,并且会得到以下打印输出:
6.5
6
6.6
我最好的猜测是类型推断存在问题,涉及 List
的类型参数。它没有采用传递给 sums
的实际类型参数,而是采用类型约束 num
作为其推断类型。结果,类型系统看到您将 num
添加到 T extends num
,然后将其分配给后者。 (解释一下,假设 T
是 int
。num
加上 int
将导致 num
。然后尝试将其分配给 {{1 }} 会导致类型错误,因为所有类型系统都知道,int
实际上可能是 num
。)
无论如何,一旦您按照错误的建议进行操作并将 double
的元素转换为 list
,错误就会消失:
T
然而,有趣的是,无论转换如何,使用加法赋值都会导致相同的错误:
void sums<T extends num>(List<T> list) {
T res = list[0] as T;
for (var i = 1; i < list.length; i++) {
res = res + list[i] as T;
}
print(res);
}
// Prints:
//
// 6.5
// 6
// 6.6
编辑:I've filed an issue for this topic on the Dart SDK Github page.
编辑 2:事实证明这不是错误,而是作为 2.12 的一部分对 Dart 进行了预期更改的结果。有关详细信息,请参阅 Irn 的回答。