无法将“num”类型的值分配给“T”类型的变量

Muh*_*wil 5 generics methods types dart flutter

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

无法将“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);
}
Run Code Online (Sandbox Code Playgroud)

lrn*_*lrn 15

这里的问题是 Dart 2.12.0 中引入的新 Null Safety 功能从语言中删除了隐式向下转型。

如果res具有类型Twhere T extends num,则该操作res + something具有静态类型num。我们唯一知道的T是它实现numnum.operator+返回num。但是,num不可分配给,T extends num因为后者是前者的子类型(T可能是int,并非所有num值都可分配给int)。因此,您需要显式强制转换才能使分配有效:

res = (res + list[i]) as T;
Run Code Online (Sandbox Code Playgroud)

就是这样的演员阵容。如果你只写res = res + list[i] as T;, 的优先级as意味着它与上面的强制转换相同。在 Dart 2.10.x 中,它无需显式强制转换即可工作,因为该语言为您插入了隐式强制转换。

如果你写res += list[i] as T;它,则意味着res = res + (list[i] as T);这是不必要的转换,因为list[i]已经有 type T,并且不会转换加法的结果。

这不会一直失败的原因int res = ...; res = res + otherInt;是,语言规范会进行int.operator+特殊处理(以及一些类似的整数运算符)并识别结果何时为整数,即使+运算符的返回类型是num。这种特殊情况不适用于T extends num.


Abi*_*n47 3

这似乎是 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);
}
Run Code Online (Sandbox Code Playgroud)

我收到你提到的错误:

main.dart:14:9: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
    res = res + list[i];
              ^
Run Code Online (Sandbox Code Playgroud)

但是,如果我在 Dart 2.10.5 中运行相同的代码,程序编译并运行不会出现问题,并且我会得到以下打印输出:

6.5
6
6.6
Run Code Online (Sandbox Code Playgroud)

我最好的猜测是,涉及类型参数的类型推断存在问题List。它似乎没有采用传递给 的实际类型参数sums,而是将类型限制num作为其推断类型。结果,类型系统发现您将 a 添加num到 a T extends num,然后将其分配给后者。(解释一下,想象T一下int。Anum加 anint会得到 a num。然后尝试将其分配给 an 会int导致类型错误,因为对于所有类型系统而言,num实际上可能是 a double。)

无论如何,一旦您执行错误建议的操作并将元素转换为listto ,错误就会消失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
Run Code Online (Sandbox Code Playgroud)

但有趣的是,无论转换如何,使用加法赋值都会导致相同的错误:

void sums<T extends num>(List<T> list) {
  T res = list[0];
  for (var i = 1; i < list.length; i++) {
    res += list[i] as T;
  }

  print(res);
}

// Prints:
//
// main.dart:14:9: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
//     res += list[i];
//         ^
Run Code Online (Sandbox Code Playgroud)

编辑:我已在 Dart SDK Github 页面上提交了有关此主题的问题。


编辑 2:事实证明这不是一个错误,而是作为 2.12 的一部分对 Dart 进行有意更改的结果。详情请参阅Irn的回答。