“num”类型的值不能分配给“T”类型的变量

时间:2021-03-20 19:39:06

标签: flutter dart generics methods types

你好,当我使用这个通用方法时,我得到这个错误

<块引用>

“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);
}

2 个答案:

答案 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,然后将其分配给后者。 (解释一下,假设 Tintnum 加上 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 的回答。