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

4

你好,当我使用这个通用方法时,出现了以下错误:

'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个回答

14
问题在于Dart 2.12.0中引入的新的Null Safety特性从语言中删除了隐式下行转换。如果`res`的类型为`T`,其中`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


3
这似乎是Dart 2.12+版本中的一个Bug或误解的功能。无论哪种情况,都值得在Dart Github页面上开个issue来解决。
如果我在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上,然后将其赋值给后者。(为了解释这一点,想象一下Tint。一个num加上一个int会得到一个num。然后试图将其分配给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

有趣的是,使用加法赋值运算符会导致相同的错误,无论转换为何种类型:
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];
//         ^

编辑:我已在Dart SDK Github页面上为此主题提交了一个问题。


编辑2:结果表明,这不是一个错误,而是作为Dart 2.12的一部分进行的有意更改的结果。有关详细信息,请参见Irn的答案。


是的,你说得对!!!这个问题在之前的版本中没有发现,希望Dart能够解决它。非常感谢,你的答案很有帮助并解决了问题。 - Muhammad Tawil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接