Edited at
DartDay 6

Dartメモ:標準入力の処理

More than 1 year has passed since last update.

自分用のメモです。


ごく単純な標準入力の受け付け

Pythonだと


Pythonでこういうの

import sys

print "START!"
for line iter(sys.stdin.readline, ""):
print line
print "DONE!"


こんな感じでサラッと書けるやつをDartだとこんなかんじ。


標準入力をprintするだけ

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)を使うなら


標準入力をprintするだけ(2)

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の forEachlisten (subscriptionを返す) をイイ感じにFutureでラップしたものらしい。


/sdk/lib/async/stream.dart

  /**

* 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が使える)で扱いやすいんじゃないかな?