0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter入門 第2回】Dart の制御構文 ― if / for / while / switch を使いこなす

0
Posted at

はじめに

前回(第1回)では Dart の変数・型・演算子を学びました。今回は 制御構文 を扱います。

プログラムの実行の流れを制御する「条件分岐」と「繰り返し」は、あらゆるアプリケーション開発で必須の知識です。

この記事で学ぶこと

  • if / else if / else
  • 三項演算子
  • for ループ(基本、for-in
  • while / do-while
  • break / continue
  • switch / case(Dart 3.0 の switch expression を含む)
  • assert

コード例はすべて DartPad で実行できます。


1. if / else if / else

基本構文

void main() {
  int score = 85;

  if (score >= 90) {
    print('評価: A');
  } else if (score >= 80) {
    print('評価: B');
  } else if (score >= 70) {
    print('評価: C');
  } else if (score >= 60) {
    print('評価: D');
  } else {
    print('評価: F');
  }
  // 評価: B
}

条件式には bool 型のみ使用可能

Dart は JavaScript とは異なり、if の条件には厳密に bool 型の値が必要です。

void main() {
  String name = 'Dart';

  // OK: bool を返す式
  if (name.isNotEmpty) {
    print('名前が入力されています: $name');
  }
  // 名前が入力されています: Dart

  // NG: 以下はコンパイルエラー
  // if (name) { }   // String は bool ではない
  // if (1) { }      // int は bool ではない
}

複合条件

void main() {
  int age = 20;
  bool hasTicket = true;

  if (age >= 18 && hasTicket) {
    print('入場できます');
  } else if (age >= 18 && !hasTicket) {
    print('チケットを購入してください');
  } else {
    print('18歳未満は入場できません');
  }
  // 入場できます
}

実践例: 成績判定

void main() {
  int japanese = 78;
  int math = 92;
  int english = 65;
  int total = japanese + math + english;     // 235
  double average = total / 3;                // 78.33333333333333

  print('国語: $japanese 点');
  print('数学: $math 点');
  print('英語: $english 点');
  print('合計: $total 点');
  print('平均: ${average.toStringAsFixed(1)} 点');  // 78.3

  if (average >= 90) {
    print('結果: 優秀');
  } else if (average >= 70) {
    print('結果: 良好');
  } else if (average >= 50) {
    print('結果: 要努力');
  } else {
    print('結果: 再試験');
  }
  // 結果: 良好
}

2. 三項演算子

条件 ? 真の値 : 偽の値 の形式で、if-else を1行で書けます。

void main() {
  int age = 17;

  String status = age >= 18 ? '成人' : '未成年';
  print('$age 歳は$status');  // 17 歳は未成年

  // 実用例: 値の範囲チェック
  int score = 105;
  int validScore = (score > 100) ? 100 : score;
  print('スコア: $validScore'); // スコア: 100

  // ネストも可能(ただし読みにくいので非推奨)
  int value = 75;
  String grade = value >= 90
      ? 'A'
      : value >= 80
          ? 'B'
          : value >= 70
              ? 'C'
              : 'D';
  print('グレード: $grade'); // グレード: C
}

3. for ループ

基本の for ループ

void main() {
  // 1 から 5 までを出力
  for (int i = 1; i <= 5; i++) {
    print('i = $i');
  }
  // i = 1
  // i = 2
  // i = 3
  // i = 4
  // i = 5
}

カウントダウン

void main() {
  for (int i = 5; i >= 1; i--) {
    print('$i...');
  }
  print('発射!');
  // 5...
  // 4...
  // 3...
  // 2...
  // 1...
  // 発射!
}

for-in ループ(コレクションの走査)

リストなどのコレクションを走査するには for-in を使います。

void main() {
  List<String> fruits = ['りんご', 'バナナ', 'みかん', 'ぶどう'];

  for (String fruit in fruits) {
    print('果物: $fruit');
  }
  // 果物: りんご
  // 果物: バナナ
  // 果物: みかん
  // 果物: ぶどう
}

インデックスとともに走査

void main() {
  List<String> languages = ['Dart', 'Python', 'Java', 'Go'];

  for (int i = 0; i < languages.length; i++) {
    print('${i + 1}番目: ${languages[i]}');
  }
  // 1番目: Dart
  // 2番目: Python
  // 3番目: Java
  // 4番目: Go
}

ネストした for ループ: 九九の表

void main() {
  for (int i = 1; i <= 9; i++) {
    String row = '';
    for (int j = 1; j <= 9; j++) {
      // padLeft で桁を揃える
      row += '${(i * j).toString().padLeft(3)}';
    }
    print(row);
  }
  //   1  2  3  4  5  6  7  8  9
  //   2  4  6  8 10 12 14 16 18
  //   3  6  9 12 15 18 21 24 27
  //   4  8 12 16 20 24 28 32 36
  //   5 10 15 20 25 30 35 40 45
  //   6 12 18 24 30 36 42 48 54
  //   7 14 21 28 35 42 49 56 63
  //   8 16 24 32 40 48 56 64 72
  //   9 18 27 36 45 54 63 72 81
}

4. while / do-while

while ループ

条件が true の間、繰り返し実行します。条件を 先に 評価するため、条件が最初から false なら一度も実行されません。

void main() {
  int count = 1;

  while (count <= 5) {
    print('count = $count');
    count++;
  }
  // count = 1
  // count = 2
  // count = 3
  // count = 4
  // count = 5

  print('ループ終了。最終 count = $count'); // ループ終了。最終 count = 6
}

do-while ループ

条件を 後に 評価するため、必ず1回は実行されます。

void main() {
  int count = 10;

  // while: 条件が最初から false なので実行されない
  while (count < 5) {
    print('while: $count');
    count++;
  }
  // (何も出力されない)

  // do-while: 必ず1回は実行される
  count = 10;
  do {
    print('do-while: $count'); // do-while: 10
    count++;
  } while (count < 5);
}

実践例: 合計が 100 を超えるまで加算

void main() {
  int sum = 0;
  int n = 1;

  while (sum <= 100) {
    sum += n;
    n++;
  }

  // ループを抜けた時点で n は最後に加算した値の次の値
  print('合計が100を超えたのは ${n - 1} まで足したとき'); // 合計が100を超えたのは 14 まで足したとき
  print('合計: $sum');                                    // 合計: 105
  // 検算: 1+2+3+...+14 = 14*15/2 = 105
}

5. break / continue

break ― ループを抜ける

void main() {
  for (int i = 1; i <= 10; i++) {
    if (i == 6) {
      print('$i で中断します');
      break;
    }
    print('i = $i');
  }
  // i = 1
  // i = 2
  // i = 3
  // i = 4
  // i = 5
  // 6 で中断します
}

continue ― 次の反復へスキップ

void main() {
  for (int i = 1; i <= 10; i++) {
    if (i % 3 == 0) {
      continue; // 3 の倍数はスキップ
    }
    print('i = $i');
  }
  // i = 1
  // i = 2
  // i = 4
  // i = 5
  // i = 7
  // i = 8
  // i = 10
}

実践例: リストから特定の要素を探す

void main() {
  List<int> numbers = [4, 7, 2, 9, 1, 8, 3, 6, 5];
  int target = 8;

  for (int i = 0; i < numbers.length; i++) {
    if (numbers[i] == target) {
      print('$target はインデックス $i にあります');
      break;
    }
  }
  // 8 はインデックス 5 にあります
}

6. switch / case

基本の switch 文

void main() {
  String dayOfWeek = 'Wednesday';

  switch (dayOfWeek) {
    case 'Monday':
      print('月曜日');
      break;
    case 'Tuesday':
      print('火曜日');
      break;
    case 'Wednesday':
      print('水曜日');
      break;
    case 'Thursday':
      print('木曜日');
      break;
    case 'Friday':
      print('金曜日');
      break;
    case 'Saturday':
      print('土曜日');
      break;
    case 'Sunday':
      print('日曜日');
      break;
    default:
      print('不正な値です');
  }
  // 水曜日
}

複数ケースをまとめる

Dart では複数の case をまとめるために、空の case を並べて最後にコードを記述します。

void main() {
  String day = 'Saturday';

  switch (day) {
    case 'Monday':
    case 'Tuesday':
    case 'Wednesday':
    case 'Thursday':
    case 'Friday':
      print('$day は平日です');
      break;
    case 'Saturday':
    case 'Sunday':
      print('$day は休日です');
      break;
    default:
      print('不正な値です');
  }
  // Saturday は休日です
}

Dart 3.0 の switch expression

Dart 3.0 以降では、switch として使えます。値を返す用途に最適です。

void main() {
  int httpStatusCode = 404;

  String message = switch (httpStatusCode) {
    200 => 'OK',
    301 => 'Moved Permanently',
    400 => 'Bad Request',
    403 => 'Forbidden',
    404 => 'Not Found',
    500 => 'Internal Server Error',
    _ => 'Unknown Status',
  };

  print('$httpStatusCode: $message'); // 404: Not Found
}

switch expression でパターンマッチング(Dart 3.0)

void main() {
  int score = 82;

  String grade = switch (score) {
    >= 90 => 'A',
    >= 80 => 'B',
    >= 70 => 'C',
    >= 60 => 'D',
    _ => 'F',
  };

  print('スコア $score → 評価: $grade'); // スコア 82 → 評価: B
}

注意: switch expression(=>を使う形式)と範囲パターン(>= 90 など)は Dart 3.0 以降の機能です。Flutter 3.10 以降で使用できます。


7. assert(デバッグ用)

assert は開発中(デバッグモード)にのみ有効な検証文です。条件が false のとき AssertionError が発生します。リリースビルドでは無視されます。

void main() {
  int age = 25;

  // デバッグモードでのみ実行される
  assert(age >= 0, '年齢は0以上でなければなりません');

  // age が負の値だった場合、デバッグモードでは AssertionError が発生する
  // int invalidAge = -1;
  // assert(invalidAge >= 0, '年齢は0以上でなければなりません');

  print('年齢: $age'); // 年齢: 25
}

DartPad での実行: DartPad はデバッグモードで動作するため assert が有効です。dart run コマンドでもデバッグモードがデフォルトです。dart run --enable-asserts で明示的に有効にすることもできます。


8. 実践的なコード例

FizzBuzz

プログラミングの定番問題です。1 から 30 まで順番に出力し、3 の倍数なら Fizz、5 の倍数なら Buzz、両方の倍数なら FizzBuzz を出力します。

void main() {
  for (int i = 1; i <= 30; i++) {
    if (i % 15 == 0) {
      print('FizzBuzz');
    } else if (i % 3 == 0) {
      print('Fizz');
    } else if (i % 5 == 0) {
      print('Buzz');
    } else {
      print(i);
    }
  }
  // 1
  // 2
  // Fizz
  // 4
  // Buzz
  // Fizz
  // 7
  // 8
  // Fizz
  // Buzz
  // 11
  // Fizz
  // 13
  // 14
  // FizzBuzz
  // 16
  // ... (以降同様)
}

リストの集計

void main() {
  List<int> scores = [85, 92, 78, 96, 64, 88, 73, 91];

  int sum = 0;
  int max = scores[0];
  int min = scores[0];
  int passCount = 0; // 80点以上を合格とする

  for (int score in scores) {
    sum += score;
    if (score > max) {
      max = score;
    }
    if (score < min) {
      min = score;
    }
    if (score >= 80) {
      passCount++;
    }
  }

  double average = sum / scores.length;

  print('受験者数: ${scores.length}');     // 受験者数: 8
  print('合計点: $sum');                    // 合計点: 667
  print('平均点: ${average.toStringAsFixed(1)}'); // 平均点: 83.4
  print('最高点: $max');                    // 最高点: 96
  print('最低点: $min');                    // 最低点: 64
  print('合格者数: $passCount');            // 合格者数: 5
  // 検算: 85+92+78+96+64+88+73+91 = 667
  // 平均: 667/8 = 83.375 → 83.4
  // 80点以上: 85, 92, 96, 88, 91 → 5人
}

素数判定

void main() {
  for (int n = 2; n <= 30; n++) {
    bool isPrime = true;

    for (int i = 2; i * i <= n; i++) {
      if (n % i == 0) {
        isPrime = false;
        break;
      }
    }

    if (isPrime) {
      print('$n は素数');
    }
  }
  // 2 は素数
  // 3 は素数
  // 5 は素数
  // 7 は素数
  // 11 は素数
  // 13 は素数
  // 17 は素数
  // 19 は素数
  // 23 は素数
  // 29 は素数
}

練習問題

練習問題 1: うるう年判定

西暦 year がうるう年かどうかを判定するプログラムを作成してください。

うるう年の条件:

  1. 4 で割り切れる年はうるう年
  2. ただし、100 で割り切れる年はうるう年ではない
  3. ただし、400 で割り切れる年はうるう年

以下の年を判定してください: 2024, 1900, 2000, 2025

期待する出力:

2024年はうるう年です
1900年はうるう年ではありません
2000年はうるう年です
2025年はうるう年ではありません
模範解答
void main() {
  List<int> years = [2024, 1900, 2000, 2025];

  for (int year in years) {
    bool isLeapYear;

    if (year % 400 == 0) {
      isLeapYear = true;
    } else if (year % 100 == 0) {
      isLeapYear = false;
    } else if (year % 4 == 0) {
      isLeapYear = true;
    } else {
      isLeapYear = false;
    }

    if (isLeapYear) {
      print('$year年はうるう年です');
    } else {
      print('$year年はうるう年ではありません');
    }
  }
}

ポイント: 条件の優先順位に注意してください。400 で割り切れるかを最初にチェックし、次に 100、最後に 4 の順で判定します。順番を間違えると正しく判定できません。

  • 2024: 400で割り切れない → 100で割り切れない → 4で割り切れる → うるう年
  • 1900: 400で割り切れない → 100で割り切れる → うるう年ではない
  • 2000: 400で割り切れる → うるう年
  • 2025: 400で割り切れない → 100で割り切れない → 4で割り切れない → うるう年ではない

練習問題 2: 三角形の描画

* を使って、高さ n = 5 の三角形を描画してください。

期待する出力:

*
**
***
****
*****

さらに余力があれば、逆三角形も描画してみてください。

逆三角形の期待する出力:

*****
****
***
**
*
模範解答
void main() {
  int n = 5;

  // 三角形
  print('--- 三角形 ---');
  for (int i = 1; i <= n; i++) {
    String row = '';
    for (int j = 0; j < i; j++) {
      row += '*';
    }
    print(row);
  }

  // 逆三角形
  print('\n--- 逆三角形 ---');
  for (int i = n; i >= 1; i--) {
    String row = '';
    for (int j = 0; j < i; j++) {
      row += '*';
    }
    print(row);
  }
}

ポイント: 外側の for が行を、内側の for が各行の * の個数を制御します。逆三角形では外側のループを n から 1 に向かってデクリメントします。Dart では '*' * i のように文字列の乗算も使えるため、内側のループの代わりに print('*' * i); と書くこともできます。


練習問題 3: switch expression で月の日数を求める

月番号(1〜12)を受け取り、Dart 3.0 の switch expression を使ってその月の日数を返すプログラムを作成してください。2月は28日(うるう年は考慮不要)とします。

以下の月を判定してください: 1, 2, 4, 7, 12

期待する出力:

1月は31日あります
2月は28日あります
4月は30日あります
7月は31日あります
12月は31日あります
模範解答
void main() {
  List<int> months = [1, 2, 4, 7, 12];

  for (int month in months) {
    int days = switch (month) {
      2 => 28,
      4 || 6 || 9 || 11 => 30,
      _ => 31,
    };

    print('$month月は${days}日あります');
  }
}

ポイント: Dart 3.0 の switch expression では || で複数のパターンをまとめられます。_ はワイルドカードで、どのパターンにもマッチしなかった場合のデフォルト値を指定します。1月, 3月, 5月, 7月, 8月, 10月, 12月は31日なので、30日の月と28日の2月だけを列挙し、残りを _ で31日としています。


まとめ

構文 用途 特徴
if / else if / else 条件分岐 条件は bool 型のみ
三項演算子 ? : 簡潔な条件分岐 値を返す式として使える
for 回数指定の繰り返し for (初期化; 条件; 更新)
for-in コレクションの走査 for (要素 in コレクション)
while 条件が真の間繰り返し 条件を先に評価
do-while 条件が真の間繰り返し 必ず1回は実行
break ループ脱出 最も内側のループから脱出
continue 次の反復へスキップ 残りの処理をスキップ
switch / case 値による分岐 break が必要
switch expression 値を返す switch Dart 3.0 以降。=> 構文
assert デバッグ検証 リリースビルドでは無視

次回(第3回)は 関数の定義と使い方 を学びます。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?