【问题标题】:A value of type 'num' can't be assigned to a variable of type 'T'“num”类型的值不能分配给“T”类型的变量
【发布时间】:2021-06-17 21:33:56
【问题描述】:

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

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

【问题讨论】:

    标签: flutter dart generics methods types


    【解决方案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。尝试将其分配给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];
    //         ^
    

    编辑:I've filed an issue for this topic on the Dart SDK Github page.


    编辑 2:事实证明这不是错误,而是作为 2.12 的一部分对 Dart 进行的预期更改的结果。有关详细信息,请参阅 Irn 的答案。

    【讨论】:

    • 是的,你是对的!!!在预览版中没有发现这个问题,希望飞镖解决它。非常感谢你的回答很有帮助并解决它。
    【解决方案2】:

    这里的问题是 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

    【讨论】:

      猜你喜欢
      • 2021-09-03
      • 1970-01-01
      • 2016-07-31
      • 2021-09-15
      • 2021-07-23
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 2022-08-05
      相关资源
      最近更新 更多