在 Dart 中的迭代器上创建 sum、min、max 属性

Creating sum, min, max properties on iterators in Dart

我有以下内容,适用于 ints:

extension IterableInt on Iterable<int> {
  int get max => reduce(math.max);
  int get min => reduce(math.min);
  int get sum => reduce((a, b) => a + b);
}

我想让它更通用以包括小数并创建了这个:

extension IterableNum on Iterable<num> {
  num get max => reduce(math.max);
  num get min => reduce(math.min);
  num get sum => reduce((a, b) => a + b);
}

这些大多失败,使用以下测试:

void main(List<String> args) {
  print([1.2, 1.3, 5, 2.2].sum); //works
  print([1.2, 1.3, 5, 2.2].max); //works
  print([1.2, 1.3, 5, 2.2].min); //works
  print([1.2, 1.3, 5.0, 2.2].sum); //does not work

  print([1, 2, 3].max); //does not work
  print([1, 2, 3].min); //does not work
  print([1, 2, 3].sum); //does not work
}

decimal 案例返回的错误是:

type '(num, num) => num' is not a subtype of type '(double, double) => double' of 'combine'

int类似,在消息中指的是int而不是double

模式似乎是,如果列表中混合有 ints 和 decimals 则没问题。如果全部为 int 或全部为 decimal,则失败。

我已经使用 fold 重新定义了属性(并添加了 multiply),这有效:

extension IterableNum on Iterable<num> {
  num get max => fold(first, math.max);
  num get min => fold(first, math.min);
  num get sum => fold(0, (a, b) => a + b);
  num get multiply => fold(1, (a, b) => a * b);
}

谁能解释一下为什么 IterableNum(使用 reduce)的第一个版本不起作用?

问题是 reduce 对其参数函数非常挑剔。

A List<int>reduce 需要 int Function(int, int) 类型的函数。别无他法。如果你将这个 List<int> 转换为 List<num>,你得到的东西看起来像是期望得到一个 num Function(num, num),但实际上需要一个 int Function(int, int)。很难同时满足这两个条件(你需要 int Function(num, num),而 (a, b) => a + b 不是。 (这都是因为 Dart class 泛型是 不安全的 协变。List<int> 总是被认为是 List<num> 的子类型,即使某些函数在 List<num>).

实际上不可用

使用fold是一个很好的解决办法。它允许您指定不同于元素类型的 return 类型。它还要求您以该类型的值开头,这就是为什么不总是可以使用 fold 而不是 reduce.

的原因

它不起作用,因为您创建了更高级别的列表(num 类型的子类)。

您的(扩展)代码应该更通用(更通用)。
喜欢这个代码:extension IterableNum<T extends num> on Iterable<T>.

void main(List<String> args) {
  print([1.2, 1.3, 5, 2.2].runtimeType);
  print([1.2, 1.3, 5.0, 2.2].runtimeType);
}

结果:

List<num>
List<double>

更正代码如下:

import 'dart:math' as math;

void main(List<String> args) {
  print([1.2, 1.3, 5, 2.2].runtimeType);
  print([1.2, 1.3, 5.0, 2.2].runtimeType);

  print([1.2, 1.3, 5, 2.2].sum); //works
  print([1.2, 1.3, 5, 2.2].max); //works
  print([1.2, 1.3, 5, 2.2].min); //works
  print([1.2, 1.3, 5.0, 2.2].sum); // WORKS!!!

  print([1, 2, 3].max); // WORKS!!!
  print([1, 2, 3].min); // WORKS!!!
  print([1, 2, 3].sum); // WORKS!!!
}

extension IterableNum<T extends num> on Iterable<T> {
  T get max => reduce(math.max);
  T get min => reduce(math.min);
  T get sum => reduce((a, b) => a + b as T);
}

结果:

List<num>
List<double>
9.7
5
1.2
9.7
3
1
6