singleWhere 方法

Future<T> singleWhere(
  1. bool test(
    1. T element
    ),
  2. {T orElse(
      )?}
    )

    在该流中查找匹配 test 的单个元素。

    返回一个未来,它完成于该流的单个元素,对于该元素,test 返回 true

    如果在流完成之前没有找到此类元素,并且提供了 orElse 函数,则调用 orElse 的结果成为未来的值。如果 orElse 抛出异常,则返回的未来完成于该错误。

    只能匹配一个元素。如果找到超过一个匹配元素,则无论是否传递了 orElse,都会抛出错误。

    如果该流在任何点发出错误,则返回的未来完成于该错误,并且取消订阅。

    在流完成之前无法提供非错误结果。

    类似于 lastWhere,但是如果在流中出现多个匹配元素,则会导致错误。

    示例

    var result = await Stream.fromIterable([1, 2, 3, 6, 9, 12])
        .singleWhere((element) => element % 4 == 0, orElse: () => -1);
    print(result); // 12
    
    result = await Stream.fromIterable([2, 6, 8, 12, 24, 32])
        .singleWhere((element) => element % 9 == 0, orElse: () => -1);
    print(result); // -1
    
    result = await Stream.fromIterable([2, 6, 8, 12, 24, 32])
        .singleWhere((element) => element % 6 == 0, orElse: () => -1);
    // Throws.
    

    实现

    Future<T> singleWhere(bool test(T element), {T orElse()?}) {
      _Future<T> future = new _Future<T>();
      late T result;
      bool foundResult = false;
      StreamSubscription<T> subscription =
          this.listen(null, onError: future._completeError, onDone: () {
        if (foundResult) {
          future._complete(result);
          return;
        }
        if (orElse != null) {
          _runUserCode(orElse, future._complete, future._completeError);
          return;
        }
        try {
          throw IterableElementError.noElement();
        } catch (e, s) {
          _completeWithErrorCallback(future, e, s);
        }
      }, cancelOnError: true);
    
      subscription.onData((T value) {
        _runUserCode(() => test(value), (bool isMatch) {
          if (isMatch) {
            if (foundResult) {
              try {
                throw IterableElementError.tooMany();
              } catch (e, s) {
                _cancelAndErrorWithReplacement(subscription, future, e, s);
              }
              return;
            }
            foundResult = true;
            result = value;
          }
        }, _cancelAndErrorClosure(subscription, future));
      });
      return future;
    }