Flutterアプリケーション開発概論

【実践】基本プログラム作成

この節の目的は、ここまで学んだ 変数・型・null safety・条件分岐・ループ・関数 を使って、ひとつの小さなプログラムを自分で組み立てられるようになることです。Dart は 2011年に Google が公開した言語で、現在は Flutter の主要言語として使われていますが、学習の入口では「大きなアプリ」を作る前に、小さな処理を最後まで自力でつなぐ 練習がとても重要です。Dart 公式も、言語の基本要素として変数、制御構文、関数、コレクションを押さえたうえで、実際にコードを書きながら理解を深める流れを示しています。

歴史的に見ると、「小さな部品を組み合わせてひとつの処理を作る」という考え方は、かなり古くからあります。1956年の FORTRAN Programmer’s Reference Manual には FUNCTIONSUBROUTINE があり、計算処理を部品として分ける発想がすでに見られます。さらに 1970年の Edsger W. Dijkstra の Notes on Structured Programming では、プログラムを 連接 sequence、選択 selection、反復 repetition の組み合わせで考える見方が整理されました。この節でやる実践は、まさにその考え方を小さなプログラムで体験するものです。

1. この節で作るもの

今回は、初心者でも流れを追いやすいように、「3教科の点数を受け取り、合計・平均・判定を表示するプログラム」 を作ります。学校のテスト結果を整理するイメージなので、何をしているか想像しやすいはずです。

このプログラムでは、次の要素を使います。

  • 変数
  • List
  • for ループ
  • 関数
  • if による条件分岐
  • 戻り値

つまり、第2章のここまでで学んだ内容を、ひとつの流れへまとめる練習です。

2. まずは完成形を見る

最初に、完成形のコードを見ます。全部をすぐ理解しなくて大丈夫です。まずは「こういう形になるのだな」と眺めてください。

void main() {
  String studentName = 'Aoi';
  List<int> scores = [78, 92, 65];

  int total = calculateTotal(scores);
  double average = calculateAverage(scores);
  String result = judgeResult(average);

  print('生徒名: $studentName');
  print('点数: $scores');
  print('合計: $total');
  print('平均: ${average.toStringAsFixed(1)}');
  print('判定: $result');
}

int calculateTotal(List<int> scores) {
  int total = 0;

  for (int score in scores) {
    total += score;
  }

  return total;
}

double calculateAverage(List<int> scores) {
  int total = calculateTotal(scores);
  return total / scores.length;
}

String judgeResult(double average) {
  if (average >= 80) {
    return 'とても良い';
  } else if (average >= 60) {
    return '合格';
  } else {
    return '再提出';
  }
}

このコードは、3教科の点数をもとに、合計、平均、判定を順番に出します。ここで大切なのは、全部を main() に詰め込まず、役割ごとに関数へ分けていることです。これが「基本プログラム作成」の大事な感覚です。Dart 公式でも、関数を使って処理をまとめる構成が基本として説明されています。

3. main()は「入口」

Dart プログラムは、普通 main() から始まります。main() は、このプログラムの入口です。ここで入力データを用意し、必要な関数を呼び出し、最後に結果を表示します。Dart の言語紹介でも main() は基本の実行開始点として示されています。

今回の main() をもう一度見てみます。

void main() {
  String studentName = 'Aoi';
  List<int> scores = [78, 92, 65];

  int total = calculateTotal(scores);
  double average = calculateAverage(scores);
  String result = judgeResult(average);

  print('生徒名: $studentName');
  print('点数: $scores');
  print('合計: $total');
  print('平均: ${average.toStringAsFixed(1)}');
  print('判定: $result');
}

ここでは、次の順で動いています。

  1. 生徒名と点数一覧を用意する
  2. 合計を計算する
  3. 平均を計算する
  4. 平均から判定を決める
  5. 最後に全部表示する

この流れを見ると、プログラムは特別な魔法ではなく、手順を順番に書いたものだと分かります。

4. Listで複数の点数を持つ

今回のプログラムでは、点数を List<int> で持っています。

List<int> scores = [78, 92, 65];

List<int> は、「整数だけを並べたリスト」という意味です。789265 の3つの点数をまとめて持てます。Dart の built-in types には List が含まれており、複数の値を順番付きで扱う基本的な型として使われます。

ここで初心者がよくやる失敗は、点数を別々の変数へ分けすぎることです。

int math = 78;
int english = 92;
int science = 65;

これでも動きますが、教科数が増えると扱いづらくなります。List を使うと、「同じ種類のデータをまとめる」という感覚が育ちます。これは後のループ処理とも相性がよいです。

5. 合計を出す関数を作る

次に、calculateTotal() を見ます。

int calculateTotal(List<int> scores) {
  int total = 0;

  for (int score in scores) {
    total += score;
  }

  return total;
}

この関数は、点数一覧を受け取って、合計点を返します。

ここで大切なのは三つです。

5-1. 引数

List<int> scores

これは引数です。外から点数一覧を受け取ります。

5-2. ループ

for (int score in scores)

for-in を使って、scores の中身をひとつずつ取り出しています。Dart 公式でも、Iterable の要素を順に扱うときに for-in が基本的な書き方として示されています。

5-3. 戻り値

return total;

最終的に合計を返しています。戻り値型が int なので、「整数を返す関数」だと読み手に分かります。

このように、関数は 入力を受け取って、処理して、結果を返す部品です。この考え方は、FORTRAN の FUNCTION や ALGOL 60 の procedure / parameter の流れとつながっています。

6. 平均を出す関数を作る

次は calculateAverage() です。

double calculateAverage(List<int> scores) {
  int total = calculateTotal(scores);
  return total / scores.length;
}

ここでは面白いことが起きています。関数の中で別の関数を使っているのです。

  • calculateTotal(scores) で合計を出す
  • scores.length で件数を調べる
  • 合計 ÷ 件数で平均を出す 戻り値型が double なのは、平均には小数が出ることがあるからです。たとえば 235 / 3 は整数ではなく小数になります。ここで int を返す設計にすると、情報を落としてしまうことがあります。つまり、型設計は「どんな結果を返したいか」に合わせて決める必要があります。Dart は intdouble を区別する built-in types を持っており、数値の意味を型で分けられます。

7. 判定を返す関数を作る

次は判定です。

String judgeResult(double average) {
  if (average >= 80) {
    return 'とても良い';
  } else if (average >= 60) {
    return '合格';
  } else {
    return '再提出';
  }
}

ここでは if / else if / else を使っています。平均点によって返す文字列を変えています。

この関数でのポイントは、「判定そのもの」を bool で返すのではなく、表示用の結果文字列として String を返していることです。前の 2-6 で学んだ通り、型設計では「この結果をどう使うか」を考える必要があります。今回は画面へそのまま出したいので String が自然です。

もし「合格か不合格かだけ」でよいなら、次のような設計もできます。

bool isPassing(double average) {
  return average >= 60;
}

どちらが正しいというより、目的によって返す型が変わるのです。ここが型設計のおもしろいところです。

8. main()に全部書かない理由

初心者は最初、全部 main() に書きたくなります。たしかに小さいコードなら動きます。たとえば次のような形です。

void main() {
  List<int> scores = [78, 92, 65];
  int total = 0;

  for (int score in scores) {
    total += score;
  }

  double average = total / scores.length;

  if (average >= 80) {
    print('とても良い');
  } else if (average >= 60) {
    print('合格');
  } else {
    print('再提出');
  }
}

これでも動きます。けれど、あとで「合計だけ別の場所でも使いたい」「平均の計算だけテストしたい」「判定基準を変えたい」となったとき、全部が一か所にあると直しにくいです。

Edsger W. Dijkstra は structured programming の中で、プログラムを整理された構造で考える重要性を強調しました。ここでの関数分割も、その延長にあります。つまり、読めること、直せること、再利用できることが大切なのです。

9. 改良してみる

せっかくなので、もう少しだけ実用的にします。たとえば、生徒が0人なら平均は計算できません。こういうとき、条件を足せます。

double calculateAverage(List<int> scores) {
  if (scores.isEmpty) {
    return 0;
  }

  int total = calculateTotal(scores);
  return total / scores.length;
}

isEmpty は、リストが空かどうかを表す bool です。こういう小さな防御を入れると、コードが少しずつ強くなります。Dart のコレクションは、長さや空判定などを備えており、こうしたチェックを書きやすくしています。

10. 実践の見方を変える

ここで一つ、新しい見方を持ってください。このプログラムは「点数管理」のコードですが、考え方は他の場面にもそのまま使えます。

たとえば、

  • お店の商品の価格一覧から合計金額を出す
  • 3回の練習記録から平均タイムを出す
  • 1週間のアクセス数から平均を出して判定する
  • アンケート結果を集計してコメントを返す このように、入力を受け取り、計算し、判定し、返す という形は広く使えます。だから、この節はただの点数計算ではなく、「基本プログラムの骨格」を学んでいるのです。

11. 練習問題

問題1

次のコードは何を表示しますか。

void main() {
  List<int> scores = [10, 20, 30];
  int total = 0;

  for (int score in scores) {
    total += score;
  }

  print(total);
}

問題2

次の関数の戻り値型として最も自然なのは何ですか。

「点数の一覧を受け取り、平均点を返す関数」

  1. bool
  2. double
  3. String

問題3

次のコードで judgeResult(85) の戻り値は何ですか。

String judgeResult(double average) {
  if (average >= 80) {
    return 'とても良い';
  } else if (average >= 60) {
    return '合格';
  } else {
    return '再提出';
  }
}

問題4

次の関数は何をしているか、一文で説明してください。

int countItems(List<String> items) {
  return items.length;
}

問題5

main() に全部書くより、関数へ分けるメリットを一つ書いてください。

問題6

次のコードの出力は何ですか。

double calculateAverage(List<int> scores) {
  int total = 0;

  for (int score in scores) {
    total += score;
  }

  return total / scores.length;
}

void main() {
  print(calculateAverage([80, 70]));
}

12. 練習問題の答え

答え1

60 を表示します。10 + 20 + 30 = 60 だからです。

答え2

正解は **2. **double です。 平均点は小数になることがあるので、double が自然です。

答え3

とても良い です。85 >= 80 が真だからです。

答え4

例です。

「文字列の一覧を受け取り、その件数を返す関数」です。

答え5

例です。

「あとで同じ処理を再利用しやすくなる」

「直す場所が一か所で済む」

「コードの意味が分かりやすくなる」

のどれかが書ければよいです。

答え6

75.0 を表示します。80 + 70 = 150 で、150 / 2 = 75.0 だからです。

13. まとめ

この節では、ここまで学んだ基本文法をつないで、ひとつの小さなプログラムを完成させました。大切だったのは、変数で値を持ち、List で複数データをまとめ、for で合計し、関数で処理を分け、if で判定する、という流れです。これは Dart の基礎文法をばらばらに覚えるのではなく、ひとつの手順として組み立てる 練習でした。Dart 公式でも、言語の基本要素を組み合わせてコードを書くことが学習の中心に置かれています。

歴史的には、FORTRAN の FUNCTION / SUBROUTINE が計算処理の部品化を進め、ALGOL 60 が手続きと引数の考え方を整理し、Dijkstra が構造化プログラミングの見方を強めました。今みなさんが Dart で書いている小さなプログラムは、その流れの延長線上にあります。つまり、「基本プログラム作成」は単なる練習ではなく、プログラムを整理して組み立てる感覚を身につけるための大切な一歩です。

次節では、ここまでの内容を使って、もう少し自分で考えながら書く演習へ進みます。

参考文献

教材トップへ戻る