0

有人可以解释以下代码有什么问题。我对函数 fInputData 进行了两次调用。第一个工作正常,第二个导致错误:“未处理的异常”“坏状态:流已经有订阅者”

我需要编写一个输入多个参数的测试控制台程序。

import "dart:async" as async;
import "dart:io"; 

void main() {
  fInputData ("Enter Nr of Iterations : ")
  .then((String sResult){
    int iIters;
    try {
      iIters = int.parse(sResult);
      if (iIters < 0) throw new Exception("Invalid");
    } catch (oError) {
      print ("Invalid entry");
      exit(1);
    }

    print ("In Main : Iterations selected = ${iIters}");

    fInputData("Continue Processing? (Y/N) : ")   // this call bombs
    .then((String sInput){
      if (sInput != "y" && sInput != "Y")
        exit(1);

      fProcessData(iIters);

      print ("Main Completed");
    });
  });
}

async.Future<String> fInputData(String sPrompt) {
  async.Completer<String> oCompleter = new async.Completer(); 

  stdout.write(sPrompt);
  async.Stream<String> oStream = stdin.transform(new StringDecoder());
  async.StreamSubscription oSub;
  oSub = oStream.listen((String sInput) {
    oCompleter.complete(sInput);
    oSub.cancel();
  });
  return oCompleter.future;
}

void fProcessData(int iIters) {
  print ("In fProcessData");
  print ("iIters = ${iIters}");

  for (int iPos = 1; iPos <= iIters; iPos++ ) {
    if (iPos%100 == 0) print ("Processed = ${iPos}");
  }
  print ("In fProcessData - completed ${iIters}");
} 
4

1 回答 1

2

一些背景阅读

Streams 有两种形式:单个或多个(也称为广播)订阅者。默认情况下,我们的流是单订阅者流。这意味着如果您尝试多次收听流,您将收到异常,并且使用任何回调函数或未来属性都算作收听。

您可以使用asBroadcastStream () 方法将单订阅者流转换为广播流。

所以你有两个选择——要么重用一个订阅对象。即调用一次listen,并保持订阅对象处于活动状态。

或者使用广播流 - 请注意广播流和单订阅者流之间存在许多差异,您需要阅读这些内容并确保它们适合您的用例。

这是一个重用订阅者提出多个问题的示例:

import 'dart:async';
import 'dart:io';

main() {
    var console = new Console();
    var loop;
    loop = () => ask(console).then((_) => loop());
    loop();
}

Future ask(Console console) {
    print('1 + 1 = ...');
    return console.readLine().then((line) {
        print(line.trim() == '2' ? 'Yup!' : 'Nope :(');
    });
}

class Console {
    StreamSubscription<String> _subs;

    Console() {
        var input = stdin
            .transform(new StringDecoder())
            .transform(new LineTransformer());

        _subs = input.listen(null);
    }

    Future<String> readLine() {
        var completer = new Completer<String>();
        _subs.onData(completer.complete);
        return completer.future;
    }
}
于 2013-05-09T20:17:42.977 回答