如何在Dart中创建StreamTransformer?

时间:2015-01-04 13:15:02

标签: stream dart transformer

尝试构建一个自定义的StreamTransformer类,但是很多示例似乎已经过时了,文档中找到的那个(不管怎么说有些类型的语言可能会考虑)作为一个类(见https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.StreamTransformer)。这似乎不像是一种类似Dart的方式来接近它,而更像是一种类似Javascript的方式(我使用Dart来避免)。

许多在线消息人士都说这是你创建StreamTransformer的方式,但扩展它时会出错。

class exampleStreamTransformer extends StreamTransformer
{
  //... (This won't work)
}

'器具'似乎是要走的路,同时实现所需的绑定功能:

class exampleStreamTransformer implements StreamTransformer
{
  Stream bind(Stream stream)
  {
    //... (Go on to return new stream, etc)
  }
}

我似乎无法找到这种方式的任何示例,但我自己也抛出了一些东西(我的IDE已经接受了,但是在运行时没有被接受,我得到一个null对象错误)尝试使用暂停吸气剂):

class exampleStreamTransformer implements StreamTransformer
{
  StreamController<String> _controller;
  StreamSubscription<String> _subscription;

  Stream bind(Stream stream)
  {
    _controller = new StreamController<String>(
        onListen: ()
        {
          _subscription = stream.listen((data)
          {
            // Transform the data.
            _controller.add(data);
          },
          onError: _controller.addError,
          onDone: _controller.close,
          cancelOnError: true); // Unsure how I'd pass this in?????
        },
        onPause: _subscription.pause,
        onResume: _subscription.resume,
        onCancel: _subscription.cancel,
        sync: true
    );

    return _controller.stream;
  }
}

希望以这种方式实现这一目标,例如“键入”字样。制作课程的方式,非常感谢任何帮助,谢谢。

5 个答案:

答案 0 :(得分:5)

为什么不使用StreamTransformer.fromHandler()

import 'dart:async';

void handleData(data, EventSink sink) {
  sink.add(data*2);
}

void main() {
  StreamTransformer doubleTransformer = new StreamTransformer.fromHandlers(handleData: handleData);

  StreamController controller = new StreamController();
  controller.stream.transform(doubleTransformer).listen((data) {
    print('data: $data');
  });

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

<强>输出

data: 2
data: 4
data: 6

答案 1 :(得分:5)

好。这是另一个工作示例:

import 'dart:async';

class DuplicateTransformer<S, T> implements StreamTransformer<S, T> {
  StreamController _controller;

  StreamSubscription _subscription;

  bool cancelOnError;

  // Original Stream
  Stream<S> _stream;

  DuplicateTransformer({bool sync: false, this.cancelOnError}) {
    _controller = new StreamController<T>(onListen: _onListen, onCancel: _onCancel, onPause: () {
      _subscription.pause();
    }, onResume: () {
      _subscription.resume();
    }, sync: sync);
  }

  DuplicateTransformer.broadcast({bool sync: false, bool this.cancelOnError}) {
    _controller = new StreamController<T>.broadcast(onListen: _onListen, onCancel: _onCancel, sync: sync);
  }

  void _onListen() {
    _subscription = _stream.listen(onData,
      onError: _controller.addError,
      onDone: _controller.close,
      cancelOnError: cancelOnError);
  }

  void _onCancel() {
    _subscription.cancel();
    _subscription = null;
  }

  /**
   * Transformation
   */

  void onData(S data) {
    _controller.add(data);
    _controller.add(data); /* DUPLICATE EXAMPLE!! REMOVE FOR YOUR OWN IMPLEMENTATION!! */
  }

  /**
   * Bind
   */

  Stream<T> bind(Stream<S> stream) {
    this._stream = stream;
    return _controller.stream;
  }
}

void main() {
  // Create StreamController
  StreamController controller = new StreamController.broadcast();
  // Transform
  Stream s = controller.stream.transform(new DuplicateTransformer.broadcast());

  s.listen((data) {
    print('data: $data');
  }).cancel();

  s.listen((data) {
    print('data2: $data');
  }).cancel();

  s.listen((data) {
    print('data3: $data');
  });

  // Simulate data

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

让我补充一些注意事项:

  • 在查看其他飞镖内部变压器的源代码时,使用implements似乎是正确的方法。
  • 我为常规流和广播流实现了两个版本。
  • 如果是常规流,您可以直接在新流控制器上调用取消/暂停/重新连接,因为我们只能听一次。
  • 如果您使用广播流,我发现只有在没有人收听流时才会调用listen()。 onCancel表现相同。如果最后一个订阅者取消其订阅,则调用onCancel。这就是为什么在这里使用相同的功能是安全的。

答案 2 :(得分:2)

DataFrame.replace

  

您可以使用StreamTransformer.fromHandlers轻松创建   只将输入事件转换为输出事件的变换器。

     

示例:

{{1}}

答案 3 :(得分:2)

map不同,转换器具有更强大的功能,可让您维护内部状态并在需要时发出值。它可以实现map无法做到的事情,例如延迟,复制,省略某些值等等。

本质上,该实现需要一个bind方法和一个cast方法,该方法基于传入的旧流提供一个新流,该方法有助于在运行时进行类型检查。

>

这是实现“ TallyTransformer”的一个过分简化的示例,该“ TallyTransformer”将整数值流转换为总和流。例如,如果到目前为止输入流具有1, 1, 1, -2, 0, ...,则输出流将是1, 2, 3, 1, 1, ...,即,将到目前为止的所有输入相加。

用法示例:stream.transform(TallyTransformer())

class TallyTransformer implements StreamTransformer {
  StreamController _controller = StreamController();
  int _sum = 0; // sum of all values so far

  @override
  Stream bind(Stream stream) {
    // start listening on input stream
    stream.listen((value) {
      _sum += value; // add the new value to sum
      _controller.add(_sum); // emit current sum to our listener
    });
    // return an output stream for our listener
    return _controller.stream;
  }

  @override
  StreamTransformer<RS, RT> cast<RS, RT>() {
    return StreamTransformer.castFrom(this);
  }
}

此示例过于简化(但仍然可以使用),并且不涉及诸如流暂停,恢复或取消之类的情况。如果遇到"Stream has already been listened"错误,请确保流正在广播。

答案 4 :(得分:0)

如果您只想使用类似这样的函数来转换值

SELECT_FIELDS = B.COLUMN_A  INTO HOST_VAR_A
TABLE_NAME =  TABLE_A A   INNER JOIN TABLE_B B      
              ON A.ROW_ID = B.ROW_ID
WHERE_CLAUSE = A.COLUMN_B = ?

使用Stream的map方法

int handleData(int data) {
  return data * 2;
}

完整示例:

stream
  .map(handleData)
  .listen((data) {
    print('data: $data');
  });

请参见dart.dev上的more examples