【问题标题】:create a circular stream in Dart在 Dart 中创建一个循环流
【发布时间】:2015-10-16 01:17:27
【问题描述】:

我尝试编写一个聊天应用程序来与计算机聊天。用户可以编写消息并获得计算机的响应。聊天记录可能如下所示:

user: Hi
computer: Hello
user: What's your name?
computer: Bot
...

我的基于循环流的设计灵感来自Cycle.js 的想法。我有一个用户消息流,它被转换为一个计算机消息流,而这些消息又是用户消息流的输入:

    |----> user message stream ---->|
    |                               |
transform                       transform
    |                               |
    |<-- computer message stream <--|

此代码已经可以使用:

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

void main() {
  cycle(computer, user);
}

typedef Stream<T> Transform<T>(Stream<T> input);

void cycle(Transform aToB, Transform bToA) {
  var aProxy = new StreamController.broadcast();
  var b = aToB(aProxy.stream);
  var a = bToA(b);
  aProxy.add('start'); // start with user
  aProxy.addStream(a);
}

Stream<String> user(Stream<String> computerMessages) {
  computerMessages = computerMessages.asBroadcastStream();
  computerMessages.listen((message) => print('computer: $message'));
  return computerMessages.map((message) {
    stdout.write('user: ');
    return stdin.readLineSync();
  });
}

Stream<String> computer(Stream<String> userMessages) {
  var messages = <String, String>{
    "Hi": "Hello",
    "What's your name?": "Bot"
  };
  return userMessages.map((m) => messages.containsKey(m) ? messages[m] : 'What?');
}

只有一个问题。您需要一个起始值来运行循环流。因此,我将这一行放在我的函数cycle

aProxy.add('start'); // start with user

实际上,这个逻辑属于我的函数user,因为cycle 不应该知道初始值。此外,我不喜欢打印初始值。它应该只触发用户输入流。因此,我更改了cycleuser

void cycle(Transform aToB, Transform bToA) {
  var aProxy = new StreamController.broadcast();
  var b = aToB(aProxy.stream);
  var a = bToA(b);
  aProxy.addStream(a);
}

Stream<String> user(Stream<String> computerMessages) {
  computerMessages = computerMessages.asBroadcastStream();
  computerMessages.listen((message) => print('computer: $message'));
  var requestInput = new StreamController<String>.broadcast();
  requestInput.add('start'); // start with user
  requestInput.addStream(computerMessages); // continue on computer response
  return requestInput.stream.map((message) {
    stdout.write('user: ');
    return stdin.readLineSync();
  });
}

但是通过这个更改,我的应用程序立即终止,标准输出中没有任何消息。怎么了?

【问题讨论】:

  • 我没有尝试完全理解代码的作用。我怀疑您需要将aProxyab(或至少其中一个)设为顶级变量。

标签: stream dart


【解决方案1】:

我找到了解决方案。在user 中创建普通而不是广播StreamController

Stream<String> user(Stream<String> computerMessages) {
  computerMessages = computerMessages.asBroadcastStream();
  computerMessages.listen((message) => print('computer: $message'));
  var requestInput = new StreamController<String>();
  requestInput.add('start'); // start with user
  requestInput.addStream(computerMessages); // continue on computer response
  return requestInput.stream.map((message) {
    stdout.write('user: ');
    return stdin.readLineSync();
  });
}

尽管我找到了解决方案,但遗憾的是我无法真正解释广播 StreamController 的问题所在。 nullrequestInput.add(null); 成功添加,但奇怪的是requestInput.addStream(computerMessages); 既没有完成,也没有computerMessages 的事件被添加到requestInput。因此,requestInput 被关闭并且应用程序终止。如果有人能提供进一步的解释,我将不胜感激。

【讨论】:

  • 原件不起作用的原因是您在调用map 之前添加了"start" 字符串。广播流不缓冲事件(它们的订阅在暂停时会缓冲,但流本身不缓冲),因此由于当时没有订阅者,事件就被丢弃了。
猜你喜欢
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 2016-10-17
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-22
相关资源
最近更新 更多