forEach与forin:调用方法时的不同行为

我注意到了这一点,forEachfor in产生了不同的行为。我有一个列表,RegExp并希望hasMatch在每个列表上运行。使用 遍历列表时forEachhasMatch永远不会返回 true。但是,如果我使用for in,则hasMatch返回 true。

示例代码:

class Foo {
  final str = "Hello";
  final regexes = [new RegExp(r"(w+)")];

  String a() {
    regexes.forEach((RegExp reg) {
      if (reg.hasMatch(str)) {
        return 'match';
      }
    });
    return 'no match';
  }

  String b() {
    for (RegExp reg in regexes) {
      if (reg.hasMatch(str)) {
        return 'match';
      }
    }
    return 'no match';
  }
}

void main() {
  Foo foo = new Foo();
  print(foo.a()); // prints "no match"
  print(foo.b()); // prints "match"
}

(带有上述示例代码的 DartPad)

方法a和之间的唯一区别ba使用forEachb使用for in,但它们产生不同的结果。为什么是这样?

回答

尽管有prefer_foreachlint,但该建议专门用于可以将其与撕下(对现有函数的引用)一起使用的情况。Effective Dart建议不要Iterable.forEach与其他任何东西一起使用,并且有相应的avoid_function_literals_in_foreach_callslint来强制执行它。

除了回调是撕裂的那些简单情况外,Iterable.forEach并不比使用基本和更通用的for循环更简单。使用 存在更多陷阱Iterable.forEach,这就是其中之一。

  • Iterable.forEach是一个将回调作为参数的函数。 Iterable.forEach不是控制结构,回调是普通函数。因此,您不能使用break来提前停止迭代或使用continue跳到下一次迭代。

  • return回调中的语句从 callback返回,返回值被忽略。的调用者Iterable.forEach永远不会收到返回的值,也永远不会有机会传播它。例如,在:

    bool f(List<int> list) {
      for (var i in list) {
        if (i == 42) {
          return true;
        }
      }
      return false;
    }
    

    return true语句从函数返回f并停止迭代。相反,与forEach

    bool g(List<int> list) {
      list.forEach((i) {
        if (i == 42) {
          return true;
        }
      });
      return false;
    }
    

    return true语句仅从回调返回。在g完成所有迭代并到达最后的return false语句之前,该函数不会返回。这也许更清楚:

    bool callback(int i) {
      if (i == 42) {
        return true;
      }
    }
    
    bool g(List<int> list) {
      list.forEach(callback);
      return false;
    }
    

    这使得更明显的是:

    1. 没有办法callback导致g返回true
    2. callback 不会沿所有路径返回值。

    (这就是你遇到的问题。)

  • Iterable.forEach不得与异步回调一起使用。因为回调返回的任何值都被忽略,所以永远不能等待异步回调。

我还应该指出,如果您启用 Dart 的新空安全功能,它启用更严格的类型检查,您的forEach代码将生成一个错误,因为它在预期具有void返回值的回调中返回一个值。


以上是forEach与forin:调用方法时的不同行为的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>