自分用のメモです。
ごく単純な標準入力の受け付け
Pythonだと
import sys
print "START!"
for line iter(sys.stdin.readline, ""):
print line
print "DONE!"
こんな感じでサラッと書けるやつをDartだとこんなかんじ。
import 'dart:io';
import 'dart:convert';
void main() async {
print("START!");
await stdin
.transform(UTF8.decoder)
.transform(const LineSplitter())
.forEach((line) {
print(line);
});
print("DONE!");
}
あるいは、普通にfor文(iterator)を使うなら
import 'dart:io';
import 'dart:convert';
import 'dart:async';
void main() async {
print("START! ---->");
Stream lines = stdin
.transform(UTF8.decoder)
.transform(const LineSplitter());
await for (val line in lines) {
print(line);
}
print("DONE!");
}
いずれにせよ、stdinがバイト列のStreamであるがゆえに、Pythonよりは若干一手間多い感じになる。
stdinまわりを少ーしだけ理解する
Stdinは、 Stream<List<Int>>
を継承していて、
それをUTF8.decoderで文字列変換して、LineSplitterで1行ずつ切り出してやることで、
イメージ通りの Stream<String>
になる。
DartのStreamは dart:async に含まれてることからもわかるように、基本的には非同期。
import 'dart:io';
import 'dart:convert';
void main() {
stdin
.transform(UTF8.decoder)
.transform(const LineSplitter());
.forEach((line) {
print(line);
})
.then((_) {
print("DONE!");
});
print("START!");
}
非同期なのがわかりやすいようにあえて変な書き方をするとこんなかんじ。
forEachかlistenか
Streamの forEach
は listen
(subscriptionを返す) をイイ感じにFutureでラップしたものらしい。
/**
* Executes [action] on each element of the stream.
*
* Completes the returned [Future] when all elements of the stream
* have been processed.
*
* If the stream contains an error, or if the call to [action] throws,
* the returned future completes with that error, and processing stops.
*/
Future forEach(void action(T element)) {
_Future future = new _Future();
StreamSubscription subscription;
subscription = this.listen(
(T element) {
// TODO(floitsch): the type should be 'void' and inferred.
_runUserCode<dynamic>(() => action(element), (_) {},
_cancelAndErrorClosure(subscription, future));
},
onError: future._completeError,
onDone: () {
future._complete(null);
},
cancelOnError: true);
return future;
}
サンプルコードだと割とlisten使っているけど、
doneとかcancelとかにそんなに興味がないとき(=大抵の場合)には forEach
の方を使っておいたほうがFuture(=async/awaitが使える)で扱いやすいんじゃないかな?