DartでFizzBuzz

最近、Dartにはまっております。

ひと通り、言語仕様ライブラリのツアーをこなしたので、ここらでひとつFizzBuzzをば。

まずはシンプルなものから。

var limit = 100;

for (var i = 1; i <= limit; i++) {
  var sb = new StringBuffer();
  if (i % 3 == 0) {
    sb.add("Fizz");
  }
  if (i % 5 == 0) {
    sb.add("Buzz");
  }
  print(sb.isEmpty ? "${i}" : sb.toString());
}

Javaっぽい。Dartの特徴は、文字列補完(${}のところ)だろうか。 式を評価できるだけではなく、DartEditorではコードの自動補完が効くので、非常に便利。

次は少し関数を意識。

fizz(i) => i % 3 == 0 ? "Fizz" : "";
buzz(i) => i % 5 == 0 ? "Buzz" : "";
for (var i = 1; i >= limit; i++) {
  var sb = new StringBuffer().add(fizz(i)).add(buzz(i));
  print(sb.isEmpty ? "${i}" : sb);
} 

Dartには文字列結合演算子が無いので、StringBufferを使わざるをえない。 (自動的にStringBufferのaddメソッド呼ぶようにコンパイラが頑張ればいいような気もするのだが)

「sb.isEmpty」はgetter。getter・setterメソッドはJavaのフィールドアクセスのように書ける。

ちょっと関数をインライン化してみた。

for (var i = 1; i <= limit; i++) {
    var sb = new StringBuffer()
                  .add(i % 3 == 0 ? "Fizz" : "")
                  .add(i % 5 == 0 ? "Buzz" : "");
    print(sb.isEmpty ? "${i}" : sb);
  }

関数定義はループ毎にされるのだろうか・・・?

そして、再帰関数。

typedef void Print(String str);

fizzbuzz(i, Print fn) {
  if (i == 0) return;
  fizzbuzz(i - 1, fn);
  var sb = new StringBuffer()
                .add(i % 3 == 0 ? "Fizz" : "")
                .add(i % 5 == 0 ? "Buzz" : "");
  fn(sb.isEmpty ? "${i}" : sb);
}

fizzbuzz(limit, print); 

無意味に継続渡ししてみた。 typedefで型エイリアス。関数のシグネチャに名前を付けるイメージ。 末尾再帰バージョンはいずれ。 (最新バージョンのM1では末尾再帰の最適化が実装されていないっぽいので意味はない)

最後は変わり種。

class FizzBuzzIterable implements Iterable<String> {

  final int limit;
  FizzBuzzIterable(this.limit);

  Iterator&lt;String&gt; iterator() {
    return new FizzBuzzIterator(this.limit);
  }
}

class FizzBuzzIterator implements Iterator<String> {
  final int limit;
  int current;

  FizzBuzzIterator(this.limit) : current = 1;

  String next() {
    var sb = new StringBuffer()
                  .add(this.current % 3 == 0 ? "Fizz" : "")
                  .add(this.current % 5 == 0 ? "Buzz" : "");
    String str = sb.isEmpty ? "${this.current}" : sb.toString();
    this.current++;
    return str;
  }

  bool get hasNext => current <= this.limit;
}</pre> 

new List.from(new FizzBuzzIterable(limit)).forEach(print);

無駄にIteratableを実装。 Javaみたく匿名クラスを定義できないっぽい。 コンストラクタの定義やgetterの定義などにDartらしさが出ている。 一度Listを生成する分無駄なのだけれど、名前付きコンストラクタ使ってみたかった。 forEachに渡してるのはprint関数の参照。ココらへんはJavaScriptっぽい。

次はIsolateあたりを使って、並列処理にチャレンジしたいなぁ

このエントリーをはてなブックマークに追加
comments powered by Disqus