dart - 使用空安全时订阅的正确编码模式?

2023-12-23

我已经启用了 dart 2.8 实验性空安全性。

我有以下退出代码。

StreamSubscription<String> subscription;
    subscription =
        response.transform(Utf8Decoder()).transform(LineSplitter()).listen(
      (line) async {
        result += line;
      },
      onDone: () async {
        unawaited(subscription.cancel());
        completer.complete(result);
      },
    );

启用 null safe 后,我在调用 subscription.cancl 的“onDone”方法中收到错误

"The expression is nullable and must be null-checked before it can be used.
Try checking that the value isn't null before using it.",

我可以通过在取消调用之前添加条件来解决问题,但这似乎没有必要,因为实际上订阅永远不会为空。

是否有一种编码模式允许将订阅声明为非空?


这里的问题是读取subscription发生在它仍然可能未分配的地方。实际上并非如此,但我们只知道因为listen方法承诺在返回之前不调用任何回调。编译器看不到这一点。所以,你需要把阅读移到作业之后。

我会做什么来做到这一点listen打电话工作:

var buffer = StringBuffer(result);
var subscription = response
  .transform(Utf8Decoder())
  .transform(LineSplitter())
  .listen((line) {
    buffer.write(line);
  });
subscription.onDone(() {
    completer.complete(buffer.toString());
  });

我删除了async来自回调,因为不需要。它使这些函数异步所做的就是返回一个没人会看到的未来。 一般来说,回调Stream and Future应该有非异步回调。

我还删除了subscription.cancel来自onDone事件处理程序。如果收到“done”事件,则订阅已完成,无需取消。

我还添加了一个字符串缓冲区,以避免重复字符串连接的二次时间和空间复杂度。

查看代码,您似乎在拆分行后立即将行连接起来,也许您需要的只是:

  response.transform(Utf8Decoder()).join("").then(completer.complete);

我现在假设拆分+连接是必要的。

在这种情况下,我实际上更愿意做的是使用listen is:

var buffer = StringBuffer();
response
  .transform(Utf8Decoder())
  .transform(LineSplitter())
  .forEach((line) {
    buffer.write(line);
  }).then(() {
    completer.complete(buffer.toString());
  }, onError: (e, s) {
    completer.completeError(e, s);
  });

或者,如果在异步函数中:

try {
  var buffer = StringBuffer();
  await for (var line in response.transform(Utf8Decoder()).transform(LineSplitter())) {
    buffer.write(line);
  }
  completer.complete(buffer.toString());  
} catch(e, s) {
  completer.completeError(e, s);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

dart - 使用空安全时订阅的正确编码模式? 的相关文章

随机推荐