
【演習】ロジック実装
この節の目的は、ここまで学んだ 変数・型・null safety・条件分岐・ループ・関数・戻り値 を使って、自分で考えて処理の流れを組み立てる力 を身につけることです。
第2章の前半では文法を一つずつ見てきましたが、この節ではそれらをつないで「小さな問題を、自分でロジックに分解して書く」練習をします。
プログラムの基本構造を「連接・選択・反復」で整理した Edsger W. Dijkstra の考え方や、FORTRAN の時代から続く「処理を部品化して組み立てる」発想は、こうした演習の土台になっています。
1. ロジック実装とは何か
ロジック実装とは、やりたいことを、順番のある処理へ変えてコードにすることです。たとえば「点数を見て合否を出したい」という願いを、そのままコードへ書くことはできません。まずは「点数を受け取る」「条件で分ける」「結果を返す」というように、小さな手順へ分ける必要があります。Dart 公式も、関数、分岐、ループ、コレクションを組み合わせて処理を書く流れを基本として説明しています。
初心者が最初につまずくのは、いきなり全部を書こうとすることです。けれど実際には、ロジック実装はいつも次の三段階で考えるとかなり楽になります。
- 入力は何か
- 途中でどんな判断や繰り返しがあるか
- 最後に何を返すか
この三つを先に言葉で決めてからコードへ入ると、かなり書きやすくなります。
2. まずは問題を日本語で分解する
今回の演習では、複数の点数から平均を出し、その平均によって評価を返すプログラム を作ります。問題をそのままコードへ飛ばさず、日本語で分解してみます。
- 点数一覧を受け取る
- 合計を計算する
- 平均を出す
- 平均に応じて評価を決める
- 結果を表示する
この分解ができると、必要な文法も見えてきます。
- 点数一覧 →
List<int> - 合計 →
forまたはfor-in - 平均 → 関数と戻り値
- 評価 →
if / else if / else - 表示 →
print()
つまり、ロジック実装は「難しいことを書く」ことではなく、問題を文法へ翻訳することです。
3. 演習1:平均点から評価を返す
最初の演習は、いちばん基本の形です。3教科の点数を持ち、平均点から評価を返します。
void main() {
List<int> scores = [80, 72, 91];
double average = calculateAverage(scores);
String grade = judgeGrade(average);
print('点数: $scores');
print('平均: ${average.toStringAsFixed(1)}');
print('評価: $grade');
}
double calculateAverage(List<int> scores) {
int total = 0;
for (int score in scores) {
total += score;
}
return total / scores.length;
}
String judgeGrade(double average) {
if (average >= 80) {
return 'とても良い';
} else if (average >= 60) {
return '合格';
} else {
return '再提出';
}
}
このコードで見てほしいのは、関数を二つに分けていることです。平均を出す仕事と、評価を決める仕事を分けると、コードの意味がかなり見やすくなります。Dart 公式でも、関数を使ってまとまりごとに役割を分ける書き方が基本です。
4. どこがロジックなのか
このコードの中で「ロジック」と呼べる部分は、特に二つあります。
一つ目は合計を出す部分です。
int total = 0;
for (int score in scores) {
total += score;
}
これは、点数一覧を一つずつ取り出して、total に足していくロジックです。
二つ目は評価を決める部分です。
if (average >= 80) {
return 'とても良い';
} else if (average >= 60) {
return '合格';
} else {
return '再提出';
}
これは、平均点によって場合分けするロジックです。
つまり、ロジック実装とは 「データをどう動かし、どこで判断するかを書くこと」 だと言えます。
5. 演習2:欠席数によってメッセージを変える
次は少しだけ別の題材にします。学校生活に寄せた例です。欠席数に応じてメッセージを変えます。
void main() {
int absences = 4;
String message = makeAttendanceMessage(absences);
print('欠席数: $absences');
print('メッセージ: $message');
}
String makeAttendanceMessage(int absences) {
if (absences == 0) {
return 'すばらしいです';
} else if (absences <= 3) {
return 'この調子でがんばりましょう';
} else {
return '体調管理にも気をつけましょう';
}
}
ここではループは使っていませんが、数値を受け取り、条件分岐で返す値を変える というロジック実装になっています。
この例で大切なのは、戻り値の型です。返しているのは表示用メッセージなので、String が自然です。前の 2-6 で学んだように、型設計は「その結果をどう使うか」で決まります。Dart は built-in types と sound null safety を持つ strongly typed language として説明されており、こうした型の選び分けがコードの意味をはっきりさせます。
6. 演習3:null safety を含むロジック
次は、値がないかもしれない場面を扱います。たとえば、ニックネームが未登録かもしれないケースです。
void main() {
String? nickname = findNickname(2);
if (nickname != null) {
print('ニックネームは $nickname です');
} else {
print('ニックネームは未登録です');
}
}
String? findNickname(int id) {
if (id == 1) {
return 'Aoi';
} else if (id == 2) {
return null;
} else {
return null;
}
}
この例では String? を使っています。? は、その値が null かもしれないことを表します。Dart の sound null safety では、non-nullable な型と nullable な型を区別し、null の可能性を型へ表します。
このロジックのポイントは、返ってきた値をそのまま使わず、まず安全確認をしていることです。ロジック実装では、「期待どおりの値が来ないかもしれない」前提を少し持つだけで、かなり壊れにくいコードになります。
7. 演習4:List とループを使って最大値を探す
少しゲームっぽい練習も入れてみます。点数一覧の中から、一番高い点数を探します。
void main() {
List<int> scores = [55, 88, 73, 91, 64];
int maxScore = findMax(scores);
print('点数一覧: $scores');
print('最高点: $maxScore');
}
int findMax(List<int> scores) {
int max = scores[0];
for (int score in scores) {
if (score > max) {
max = score;
}
}
return max;
}
このロジックは、最初の値を「今の最大」として持ち、後ろから順に比べていく流れです。
ここでは、ループと条件分岐が自然に組み合わさっています。
- ループで全部見る
- 条件分岐で比較する
- 最大値を更新する
このように、ロジック実装では 一つの文法だけで解くことは少なく、複数を組み合わせる ことが多いです。
8. ロジック実装でよくある失敗
初心者がやりやすい失敗を、ここで三つだけ整理しておきます。
8-1. いきなり全部書こうとする
問題を見た瞬間にコードを書き始めると、途中で迷いやすいです。
先に「入力」「途中の処理」「出力」を日本語で書くほうが安定します。
8-2. main() に全部書いてしまう
小さい処理でも、役割ごとに関数へ分けたほうが読みやすいです。
関数化は、後で修正しやすくするためにも重要です。
8-3. 戻り値の型をなんとなく決める
「表示したいだけなのか」「条件分岐に使いたいのか」「計算に使いたいのか」で、戻り値型は変わります。
String、bool、int、double のどれが自然かを毎回考える癖をつけると、コードがかなりきれいになります。
9. 実践:自分で少しだけ改良してみる
ここまで読めたら、次のどれかを自分で変えてみてください。
- 判定基準を 90 / 70 / それ以外へ変える
- 欠席数メッセージを 4 段階に増やす
- 最高点ではなく最低点を探す
- 点数一覧を 5 教科へ増やす
この「少し変える」作業がとても大切です。
読むだけではなく、自分で1か所でも書き換えると、理解はかなり深まります。
10. 練習問題
問題1
次のコードは何を表示しますか。
void main() {
List<int> scores = [10, 20, 30];
int total = 0;
for (int score in scores) {
total += score;
}
print(total);
}
問題2
次の関数の戻り値型として最も自然なのは何ですか。
「出席しているかどうかを返す関数」
Stringbooldouble
問題3
次のコードは何を表示しますか。
String judge(int score) {
if (score >= 80) {
return 'A';
} else if (score >= 60) {
return 'B';
} else {
return 'C';
}
}
void main() {
print(judge(75));
}
問題4
次の関数は何をしているか、一文で説明してください。
int countNames(List<String> names) {
return names.length;
}
問題5
次のコードの出力は何ですか。
int findMin(List<int> numbers) {
int min = numbers[0];
for (int number in numbers) {
if (number < min) {
min = number;
}
}
return min;
}
void main() {
print(findMin([8, 3, 10, 5]));
}
問題6
次のコードで String? を使っている理由を説明してください。
String? findMessage(bool hasData) {
if (hasData) {
return 'データがあります';
} else {
return null;
}
}
11. 練習問題の答え
答え1
60 を表示します。10 + 20 + 30 の合計だからです。
答え2
正解は **2. **bool です。
出席しているかどうかは、はい / いいえ の二択だからです。
答え3
B を表示します。75 は 80 以上ではないですが、60 以上なので B です。
答え4
例です。
「名前の一覧を受け取り、その件数を返す関数」です。
答え5
3 を表示します。
配列の中で一番小さい値だからです。
答え6
null を返す可能性があるからです。
Dart の sound null safety では、null を返す可能性がある型は ? を付けて表す必要があります。
12. まとめ
この節では、ここまで学んだ文法を使って、小さな問題をロジックへ分解して実装する練習 をしました。
平均点の計算、欠席数メッセージ、nullable な値の処理、最大値の探索などを通して、ロジック実装は「問題を文法へ翻訳すること」だと分かったはずです。
Dart の基本要素である関数、分岐、ループ、コレクション、null safety を組み合わせることで、小さくても意味のあるプログラムが作れます。
歴史的には、FORTRAN の FUNCTION / SUBROUTINE が処理の部品化を早くから実用化し、ALGOL 60 が手続きと引数を整理し、Dijkstra が structured programming の中で「連接・選択・反復」の組み合わせを強調しました。
いま行っている演習は、その長い流れの現代版です。だから、ロジック実装は単なる練習問題ではなく、プログラムを組み立てる感覚そのものを育てる大事な段階だと言えます。
参考文献
- Dart Documentation, “Dart overview”
- Dart Documentation, “Dart docs”
- Dart Documentation, “Sound null safety”
- The FORTRAN Automatic Coding System for the IBM 704 EDPM: Programmer’s Reference Manual (1956)
- Edsger W. Dijkstra, Notes on Structured Programming (1970)
- Revised Report on the Algorithmic Language ALGOL 60 (1960)