狐好きぷろぐらまー

狐好きプログラマーのブログです。

【Dart】rxdartについて調べてみる 第5回目 -Periodic, Never- 【rxdart】

こんばんは。 pregum_foxです。

前回に引き続きrxdartのオペレータを調べていきたいと思います。

今回は、rxdartのPeriodicオペレータとNeverオペレータについて調べていきます。

この記事は0.22.x以前のrxdartで書かれた記事です。

この記事に書かれているサンプルコードは0.23.0以降のrxdartでは動きません。0.23.0に対応した記事については以下の記事をご覧ください。

pregum-fox.hatenablog.jp

前回までの記事です。

目次です。

動作環境

動作環境は以下の通りです。

項目 バージョン
Dart 2.5.1
rxdart 0.22.2

以下にPeriodicオペレータとNeverオペレータについて記載します。 オペレータの名称はRx、rxdart、Stream APIの順で記載します。

rxdart: Observable<T>.periodic ファクトリコンストラクタ / Stream API: Stream<T>.periodic ファクトリコンストラク

periodicは、Rxのコアのオペレータとしては存在していないようです。 ただ、いくつかのオペレータを組み合わせて代替することが可能です。(サンプルに代替版も記載します。)

シグネチャ

  • rxdart
    Observable<T> Observable<T>.periodic(Duration period, [T computation(int computationCount)])

  • Stream API
    Stream<T> Stream<T>.periodic(Duration period, [T computation(int computationCount)])

処理の概要

periodicは、period間隔で繰り返し値を作成し、発行します。
発行する値は、値を作成するごとにインクリメントされていきます。
computationが省略されている場合は、nullが作成、発行されます。
サンプルを以下に示します。

import 'package:rxdart/rxdart.dart';

/// rxdartのperiodicサンプル
void studyPeriodic() {
  // 500msごとに3にインクリメントされた値が発行されます。
  // 無限に発行される為、takeオペレータで5個だけ取得しています。
  Observable<int>.periodic(Duration(milliseconds: 500), (i) => i + 3)
      .take(5)
      .listen(print, onDone: () => print('done.'));
}
// 実行結果
// 3
// 4
// 5
// 6
// 7
// done.
  
/// periodicをRxの標準オペレータで代替した場合
void imitationPeriodic() {
  Observable<int>.repeat((val) => Observable<int>.just(val))
      .interval(Duration(milliseconds: 500))
      .map((val) => 3 + val)
      .take(5)
      .listen(print, onDone: () => print('done. '));
}
// 実行結果
// 3
// 4
// 5
// 6
// 7
// done.
  
/// Stream APIのperiodicサンプル
void studyPeriodicStream() {
  Stream<int>.periodic(Duration(milliseconds: 500), (i) => i + 3)
      .take(5)
      .listen(print, onDone: () => print('done.'));
}
// 実行結果
// 3
// 4
// 5
// 6
// 7
// done.

サンプルの実行結果から、Observableな値が作成される度に出力される数がインクリメントされていることが分かります。
定期的に値を発行したい場合は使えるかもしれません。

Never オペレータ (rxdart: Observable<T>.never ファクトリコンストラクタ / NeverStream<T> クラス)

シグネチャ

  • rxdart
    Observable<T> Observable<T>.never()

  • Stream API
    NeverStream<T> NeverStream<T>()

処理の概要

無限の期間を示す場合、使用することができます。
neverオペレータを使用した場合、終了しないためonDone処理も実行されません。
サンプルを以下に示します。

/// rxdartのNeverオペレータサンプル
void studyNever() {
  // neverオペレータで無限の期間を表現できます。
  // timeoutオペレータをchainすることで、時間切れを確実に起こすことができます。
  Observable<String>.never()
      .timeout(Duration(seconds: 3),
          onTimeout: (err) => err.addError('time out error'))
      .listen((str) => print('listen: $str'),
          onError: (err) => print('error listen: $err'), cancelOnError: true);
}
// 実行結果
// error listen: time out error

/// Stream APIのNeverオペレータサンプル
void studyNeverStream() {
  NeverStream<String>()
      .timeout(Duration(seconds: 3),
          onTimeout: (err) => err.addError('time out error'))
      .listen((str) => print('listen: $str'),
          onError: (err) => print('error listen: $err'), cancelOnError: true);
}
// 実行結果
// error listen: time out error

サンプルの実行結果を見てもらうとわかるように、neverオペレータだけでは終了しないため、timeoutオペレータを組み合わせてtimeout時にerrorを起こすようにしています。
このような時間切れのテストを書く際に、neverオペレータを使用すれば簡単に実装することができます。 errorで終了する際は、cancelOnErrorをtrueする必要がある事にご注意ください。(デフォルトのfalseのままだと、onErrorの処理の後onDoneの処理が走ります。)

雑感

Rxの主要なオペレータを調べてrxdartの内容と見比べてみたりしていますが、対応するオペレータがまだわからないのでRxは調べれば調べるほど深みにはまっている感じがあります。。

ある程度のところでこの沼から脱出できることを思いながら調べていきたいと思います。

ここまで読んで頂き、ありがとうございました。

参考サイト