okuzawatsの日記

モバイルアプリケーション開発の沼💀

DartでFizzBuzz

書いている人

モバイルアプリケーションアーキテクトとして働いています。モバイルアプリケーションのアーキテクチャ、自動テスト、CI/CDに興味があります。


FizzBuzzを書いてDartを味わっていきます。

まずは引数として整数 n を受け取り、整数 n に対するFizzBuzzを返す関数を実装します。結論から言うとこんな感じで実装しました。

/// 整数[n]に対するFizzBuzzを返す。
///
/// [n]が3の倍数の場合は"Fizz"、
/// 5の倍数の場合は"Buzz"、
/// 3の倍数かつ5の倍数の場合は"FizzBuzz"、
/// それ以外の場合は[n]の文字列表現を返す。
/// @param n FizzBuzzの元となる整数値
/// @returns [n]のFizzBuzz
String fizzBuzz(int n) {
  var s = '';
  if (n % 3 == 0) s += 'Fizz';
  if (n % 5 == 0) s += 'Buzz';
  return s.isNotEmpty ? s : '$n';
}

見どころがいくつかありますが、まずドキュメンテーションコメントです。Dartにおけるドキュメンテーションコメントに関するガイダンスがEffective Dart: Documentationに示されており、上記のコードではそのガイダンスの一部に従っています。

次に、ローカル変数 svar s = ''; で宣言しています。Effective Dartでは、 var を使って型注釈なしでローカル変数を宣言することが推奨されています。ローカル変数であれば final も使わなくてOKです(今回のコードだと再代入を行なっているのでそもそも final にはできませんが)。

Most local variables shouldn’t have type annotations and should be declared using just var or final. There are two rules in wide use for when to use one or the other:

DO follow a consistent rule for var and final on local variables

次の行では、 if (n % 3 == 0) s += 'Fizz';s に文字列を再代入しています。Dartのifには特に説明を見つけられませんでしたが、 if (Boolean) Statement というシグネチャであれば良く、真偽値がtrueの場合に実行されるStatementはブロック {} で囲っても囲わなくても良さそうです。個人的には、今回のコードで行なっているようなブロックの省略をせず、ブロックで囲んだ方がベターだとは思います(というような話を3年ほど前にしました)。

最後の return s.isNotEmpty ? s : '$n'; も味わい深いです。まず ? 演算子ですが、これはいわゆる三項演算子です。 Boolean ? Left Expression : Right Expression というシグネチャで、真偽値がtrueであればLeft Expressionの評価値を、falseであればRight Expressionの評価値を返します。また、 '$n' の記法は文字列テンプレートで、ここでは n を文字列に展開しています。

ここまででFizzBuzzを返す関数を実装し、味わってきました。なかなか味わい深かったことと思います。さらに、この関数をループ内で呼び出して1から100のFizzBuzzを標準出力します。

こちらについても結論から言うとこんな感じで実装しました。こちらも味わっていきます。

import 'src/fizzbuzz.dart';

void main() {
  Stream.fromIterable(
    List.generate(100, (i) => ++i)
  )
  .map(fizzBuzz)
  .listen(print);
}

まずは import 'src/fizzbuzz.dart'; で、先ほど書いた fizzBuzz 関数を参照できるようにしています。この関数を src/fizzbuzz.dart に置いているので、このようなimportになっています。

次に main 関数ですが、DartでHello Worldで書いたようにエントリーポイントとなる関数です。

以下の部分はDartの特徴が表れる部分かと思います。これは1から100までの整数値のストリームを作っている処理です。まずList#generateを使ってイテラブルであるListを作り、さらにString#fromIterableでストリームを作っています。 1, 2, ..., 100 までの整数値のストリームを返します。

  Stream.fromIterable(
    List.generate(100, (i) => ++i)
  )

List#generateについてはDartのリスト内包表記を使って [for (var i = 1; i <= 100; i++) i] というように書いても良いですが、List#generateを使った方が美しい気がしてます。

次に以下の部分ですが、これはStreamをマップする map 関数の引数として fizzBuzz 関数を渡しています。 map 関数にはラムダを渡すこともできます(例: .map((n) => n * 2) )。

  .map(fizzBuzz)

ストリームの末端で標準出力します。末端処理に listen 関数を使います。

  .listen(print);

早速実行してみます。

% dart main.dart 
1
2
Fizz
4
Buzz
...以下略

🎉

Reference

  1. Fizz Buzz - Wikipedia(最終アクセス日:2025年6月11日)
  2. Effective Dart: Documentation(最終アクセス日:2025年6月11日)
  3. DO follow a consistent rule for var and final on local variables(最終アクセス日:2025年6月11日)
  4. If(最終アクセス日:2025年6月11日)
  5. Kotlinのifを愛でる(最終アクセス日:2025年6月11日)
  6. DartでHello World(最終アクセス日:2025年6月11日)

Related