首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >"StreamTransformer<RS,RT> cast<RS,RT>()“做什么?

"StreamTransformer<RS,RT> cast<RS,RT>()“做什么?
EN

Stack Overflow用户
提问于 2018-11-19 10:43:15
回答 1查看 874关注 0票数 3

我已经实现了流转换器。请注意,这只是一个练习(为了学习Dart)。此转换器将整数转换为字符串。我给出了下面的代码,您也可以在GitHub上找到它。

代码语言:javascript
复制
// Conceptually, a transformer is simply a function from Stream to Stream that
// is encapsulated into a class.
//
// A transformer is made of:
// - A stream controller. The controller provides the "output" stream that will
//   receive the transformed values.
// - A "bind()" method. This method is called by the "input" stream "transform"
//   method (inputStream.transform(<the stream transformer>).

import 'dart:async';

/// This class defines the implementation of a class that emulates a function
/// that converts a data with a given type (S) into a data with another type (T).
abstract class TypeCaster<S, T> {
  T call(S value);
}

/// This class emulates a converter from integers to strings.
class Caster extends TypeCaster<int, String> {
  String call(int value) {
    return "<${value.toString()}>";
  }
}

// StreamTransformer<S, T> is an abstract class. The functions listed below must
// be implemented:
// - Stream<T> bind(Stream<S> stream)
// - StreamTransformer<RS, RT> cast<RS, RT>()

class CasterTransformer<S, T> implements StreamTransformer<S, T> {

  StreamController<T> _controller;
  bool _cancelOnError;
  TypeCaster<S, T> _caster;

  // Original (or input) stream.
  Stream<S> _stream;

  // The stream subscription returned by the call to the function "listen", of
  // the original (input) stream (_stream.listen(...)).
  StreamSubscription<S> _subscription;

  /// Constructor that creates a unicast stream.
  /// [caster] An instance of "type caster".
  CasterTransformer(TypeCaster<S, T> caster, {
    bool sync: false,
    bool cancelOnError: true
  }) {
    _controller = new StreamController<T>(
        onListen: _onListen,
        onCancel: _onCancel,
        onPause: () => _subscription.pause(),
        onResume: () => _subscription.resume(),
        sync: sync
    );
    _cancelOnError = cancelOnError;
    _caster = caster;
  }

  /// Constructor that creates a broadcast stream.
  /// [caster] An instance of "type caster".
  CasterTransformer.broadcast(TypeCaster<S, T> caster, {
    bool sync: false,
    bool cancelOnError: true
  }) {
      _cancelOnError = cancelOnError;
      _controller = new StreamController<T>.broadcast(
          onListen: _onListen,
          onCancel: _onCancel,
          sync: sync
      );
      _caster = caster;
  }

  /// Handler executed whenever a listener subscribes to the controller's stream.
  /// Note: when the transformer is applied to the original stream, through call
  ///       to the method "transform", the method "bind()" is called behind the
  ///       scenes. The method "bind()" returns the controller stream.
  ///       When a listener is applied to the controller stream, then this function
  ///       (that is "_onListen()") will be executed. This function will set the
  ///       handler ("_onData") that will be executed each time a value appears
  ///       in the original stream. This handler takes the incoming value, casts
  ///       it, and inject it to the (controller) output stream.
  /// Note: this method is called only once. On the other hand, the method "_onData"
  ///       is called as many times as there are values to transform.
  void _onListen() {
    _subscription = _stream.listen(
        _onData,
        onError: _controller.addError,
        onDone: _controller.close,
        cancelOnError: _cancelOnError
    );
  }

  /// Handler executed whenever the subscription to the controller's stream is cancelled.
  void _onCancel() {
    _subscription.cancel();
    _subscription = null;
  }

  /// Handler executed whenever data comes from the original (input) stream.
  /// Please note that the transformation takes place here.
  /// Note: this method is called as many times as there are values to transform.
  void _onData(S data) {
    _controller.add(_caster(data));
  }

  /// This method is called once, when the stream transformer is assigned to the
  /// original (input) stream. It returns the stream provided by the controller.
  /// Note: here, you can see that the process transforms a value of type
  ///       S into a value of type T. Thus, it is necessary to provide a function
  ///       that performs the conversion from type S to type T.
  /// Note: the returned stream may accept only one, or more than one, listener.
  ///       This depends on the method called to instantiate the transformer.
  ///       * CasterTransformer() => only one listener.
  ///       * CasterTransformer.broadcast() => one or more listener.
  Stream<T> bind(Stream<S> stream) {
    _stream = stream;
    return _controller.stream;
  }

  // TODO: what should this method do ? Find the answer.
  StreamTransformer<RS, RT> cast<RS, RT>() {
    return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
      // What should we do here ?
    });
  }
}


main() {

  // ---------------------------------------------------------------------------
  // TEST: unicast controller.
  // ---------------------------------------------------------------------------

  // Create a controller that will be used to inject integers into the "input"
  // stream.
  StreamController<int> controller_unicast = new StreamController<int>();
  // Get the stream "to control".
  Stream<int> integer_stream_unicast = controller_unicast.stream;
  // Apply a transformer on the "input" stream.
  // The method "transform" calls the method "bind", which returns the stream that
  // receives the transformed values.
  Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));

  string_stream_unicast.listen((data) {
    print('String => $data');
  });

  // Inject integers into the "input" stream.
  controller_unicast.add(1);
  controller_unicast.add(2);
  controller_unicast.add(3);

  // ---------------------------------------------------------------------------
  // TEST: broadcast controller.
  // ---------------------------------------------------------------------------

  StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
  Stream<int> integer_stream_broadcast = controller_broadcast.stream;
  Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));

  string_stream_broadcast.listen((data) {
    print('Listener 1: String => $data');
  });

  string_stream_broadcast.listen((data) {
    print('Listener 2: String => $data');
  });

  controller_broadcast.add(1);
  controller_broadcast.add(2);
  controller_broadcast.add(3);
}

CasterTransformer<S, T>扩展了抽象类StreamTransformer<S, T>

因此,它实现了方法StreamTransformer<RS, RT> cast<RS, RT>()

关于文件,据说:

结果转换器将在运行时检查它转换的流的所有数据事件是否实际上是S的实例,并将检查此转换器产生的所有数据事件实际上都是RT的实例。

请参阅:https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html

首先,我认为这个文档中有一个错误:应该说"...it转换实际上是RS的实例“(而不是S)。

然而,在我看来,这似乎是模糊的。

  • 为什么我们需要流转换器来检查值类型?变压器的目的是改造,不是吗?如果组件的目的是检查,那么我们为什么不称它为检查器呢?
  • 另外,为什么我们需要检查转换器(我们实现的)是否生成所需的数据?如果没有,那么我们将面临一个应该被修复的错误。

有人能解释一下Cast()方法的目的吗?

EN

回答 1

Stack Overflow用户

发布于 2018-11-19 12:46:37

cast方法可以帮助输入操作。

如果您有一个StreamTransformer<num, int>,它会将数字转换为整数(例如,调用它们上的.toInt(),然后添加42,因为这显然是有用的!)如果您想在期望StreamTransformer<int, num>的地方使用该转换器,那么您就不能使用,因为num不是int的子类型,所以转换器不能分配给该类型。

但是您知道,因为您了解流转换器实际上是如何工作的,所以第一种类型的参数只用于输入。在只有给定num的情况下,接受任何int的东西应该是安全的。因此,要使类型系统相信您知道自己在做什么,您可以这样写:

代码语言:javascript
复制
StreamTransformer<int, num> transform = myTranformer.cast<int, num>();

现在,tranformer接受任何整数(RS),检查它是否是一个num (S),将其传递给调用toInt()并添加42的myTransformer,然后返回生成的int (T),transformer检查它是否是num (RT)并发射它。

一切正常,类型系统是快乐的。

您可以使用cast来做在运行时永远无法工作的事情,因为它所做的只是添加额外的运行时检查,从而使静态类型系统确信事情要么会成功,要么会抛出这些检查。

获得StreamTransformer.cast实现的最简单方法是使用StreamTransformer.castFrom静态方法:

代码语言:javascript
复制
StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);

它将在您自己的转换器上使用系统的默认强制包装器。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53372895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档