
変数・型・null safety・List/Map 入門
この節の目的は、Dart の基本文法のうち、「データをどう持つか」 を理解することです。第2章ではこのあと条件分岐、ループ、関数へ進みますが、その前に「何を入れる箱なのか」「その箱に何を入れてよいのか」をつかまないと、後のコードが読みにくくなります。Dart は Google が 2011年に公開した言語で、現在は Flutter の基盤として使われており、型安全、型推論、sound null safety、コレクション などが言語の重要な柱になっています。
1. まずは全体像
プログラムを書くとき、最初に必要なのは「値をどこへ置くか」です。
そのために使うのが変数です。変数は、値を入れておく箱です。
そして、その箱に「文字を入れる箱」「整数を入れる箱」「真偽値を入れる箱」のようなルールを与えるのが型です。Dart 公式は、Dart を type safe な言語と説明しており、変数の値が変数の静的型に合うことを重視しています。さらに、型注釈を書かなくてもある程度は自動で推測する type inference 型推論 が使えます。
たとえば、学校の出席確認アプリを作るとします。
- 「生徒名」は文字です。
- 「欠席数」は数字です。
- 「登校したかどうか」は true / false の二択です。
このように、現実の情報をプログラムへ写すとき、まず必要なのが変数と型です。
2. 変数とは何か
変数は、値を保存してあとで使うための名前つきの箱です。
数学の x のような記号に少し似ていますが、プログラミングでは「あとで読み出せる保存場所」という意味が強いです。
次のコードを見てください。
void main() {
String studentName = 'Aoi';
int absences = 2;
bool isPresentToday = true;
print(studentName);
print(absences);
print(isPresentToday);
}
このコードでは、studentName、absences、isPresentToday という3つの変数を作っています。それぞれに文字列、整数、真偽値を入れています。
ここで大切なのは、変数名は中身が分かるように付けることです。
a や x1 のような名前でも動くことはありますが、初心者のうちは意味が分かる名前のほうが圧倒的に読みやすいです。
3. 型とは何か
型は、その変数へどんな種類の値を入れてよいかを表すルールです。
たとえば、次のような型がよく使われます。
| 型 | 意味 | 例 |
|---|---|---|
int | 整数 | 3, 10, -5 |
double | 小数 | 3.14, 0.5 |
String | 文字列 | 'hello', '青木' |
bool | 真偽値 | true, false |
Dart 公式は、Dart が built-in types 組み込み型 を持つと説明しており、int、double、String、bool、List、Set、Map などが基本として用意されています。
たとえば次のコードは正しいです。
void main() {
int age = 16;
double height = 168.5;
String club = 'Basketball';
bool likesMath = false;
print(age);
print(height);
print(club);
print(likesMath);
}
一方で、次のような代入は問題になります。
void main() {
int score = 'ninety';
print(score);
}
score は int なので、整数を入れる箱です。
そこへ文字列 'ninety' を入れようとしているので、型が合いません。
Dart の型安全性は、こうした取り違えを減らすためにあります。
4. 誰が、いつ、どんな概念を広めてきたのか
4-1. Dart 公開時の考え方
Dart は 2011年10月に Google から公開されました。
公開時の紹介では、Lars Bak と Kasper Lund が中心となって設計した言語として示され、structured web programming、つまり「構造化された web プログラミング」のための言語であることが強調されました。ここでいう構造化は、場当たり的ではなく、整理されたコードを書きやすくする方向性を指しています。
4-2. Dart 2 と型システムの強化
2018年の Dart 2 は、型システムを大きく強化した節目です。
Dart チームは Dart 2 を optimized for client-side development と紹介し、より強い型システムを備えたことを打ち出しました。つまり、「書きやすい」だけでなく「間違いを見つけやすい」方向へ言語が進んだわけです。
4-3. sound null safety の導入
2021年の Dart 2.12 では sound null safety が安定版として導入されました。
これは、Michael Thomsen による Dart 2.12 発表でも大きく扱われています。
null safety は、「値が入っていない状態」である null を、型のレベルでより安全に扱う仕組みです。しかも Dart では sound、つまり実行時にも非 null 性が保たれる仕組みとして設計されています。
4-4. Dart 3 と records / patterns
2023年の Dart 3 では、records と patterns が追加されました。
この節では records は軽く触れるだけですが、「Dart は今も進化している言語」であり、型の扱いをより表現力豊かにしている流れがあることは知っておく価値があります。
5. 型推論とは何か
Dart では、型を毎回明示しなくてもよい場面があります。
これを型推論といいます。型推論とは、代入した値などから、Dart が自動で型を推測する仕組みです。Dart 公式も、型注釈は省略できる場合があり、type inference が使えると説明しています。
たとえば、次の二つはどちらもほぼ同じ意味です。
void main() {
String schoolName = 'Prince Academy';
var classCount = 6;
print(schoolName);
print(classCount);
}
schoolName は明示的に String と書いています。classCount は var を使っていますが、6 を代入したので int と推測されます。
ここで注意したいのは、var は「何でも入れられる魔法の箱」ではないことです。
最初に入れた値をもとに型が決まり、その後はその型に合う値を使うのが基本です。
void main() {
var score = 80;
// score = 'high'; // これは型が合わず問題になる
print(score);
}
初心者は var と dynamic を混同しやすいです。
この二つは違います。
varは「型を省略しているだけ」で、実際には型推論が働く。dynamicは「動的に扱う」ため、型チェックがゆるくなる。 学習の最初は、varは使ってよいですが、dynamicはできるだけ避けるほうが理解しやすいです。Dart 公式も、dynamicは柔軟だが runtime checks 実行時チェック に依存しやすいことを説明しています。
6. null safety とは何か
6-1. null とは
null は、「値が入っていない」ことを表す特別な値です。
たとえば、まだ決まっていないニックネーム、まだ提出されていないレポート点数、まだ登録されていない電話番号などを考えると分かりやすいです。
6-2. null safety の考え方
Dart の null safety は、null を入れてよい変数と、入れてはいけない変数を分ける仕組みです。
公式は sound null safety を、static code analysis により null exception を防ぎやすくする仕組みだと説明しています。
次のコードを見てください。
void main() {
String name = 'Rin';
print(name.length);
}
この name は non-nullable、つまり null を入れてはいけない String です。
だから name.length を安心して呼びやすいのです。
一方で、次のように ? を付けると nullable になります。
void main() {
String? nickname = null;
print(nickname);
}
String? は、String かもしれないし null かもしれない型です。
この ? がとても大切です。
6-3. nullable な値をそのまま使えない理由
nullable な変数に対しては、そのまま長さを取ることができません。
void main() {
String? nickname = null;
// print(nickname.length); // そのままでは危険
}
なぜなら、nickname が null なら、長さという概念がないからです。
そこで、まず null かどうか確認します。
void main() {
String? nickname = 'Aoi';
if (nickname != null) {
print(nickname.length);
} else {
print('ニックネーム未設定');
}
}
この流れが null safety の基本です。
使う前に、安全か確認する。
これは Dart だけでなく、プログラム全体でとても大切な考え方です。
6-4. null safety が嬉しい理由
初心者のうちは「少し面倒」と感じるかもしれません。
ですが、null safety があることで、「値が入っていると思って使ったら、実は空だった」というバグをかなり減らせます。
とくにアプリ開発では、ユーザー入力、API レスポンス、データベースの値など、空かもしれない値が多いので、ここを最初に学ぶ意味は大きいです。
7. List 入門
7-1. List とは
List は、複数の値を順番に並べて持つための型です。
公式の collections ドキュメントでも、List は ordered group of objects、つまり順序を持つ値の集まりとして扱われています。
たとえば、テストの点数一覧、今日の持ち物リスト、クラス名簿などは List で表しやすいです。
void main() {
List<String> subjects = ['Math', 'English', 'Science'];
print(subjects);
print(subjects[0]);
}
subjects[0] は最初の要素です。
Dart の List は 0 番から始まります。
ここは初心者がよくつまずく点です。
7-2. List の型
List<String> のように書くと、「String だけを並べる List」という意味です。
このように、List の中身の型も指定できます。
void main() {
List<int> scores = [80, 92, 75];
print(scores);
}
これなら、点数一覧として分かりやすいです。
7-3. List の操作
要素を追加する例です。
void main() {
List<String> members = ['Aoi', 'Rin'];
members.add('Sora');
print(members);
}
要素数を調べることもできます。
void main() {
List<String> members = ['Aoi', 'Rin', 'Sora'];
print(members.length);
}
List は、このあと学ぶループとも相性がとてもよいです。
「複数のデータをまとめる箱」として、最初のうちから慣れておくと便利です。
8. Map 入門
8-1. Map とは
Map は、キーと値の組み合わせでデータを持つ型です。
たとえば「名前 → 点数」「教科 → 担当先生」「商品名 → 価格」のような対応表を作りたいときに向いています。Dart の collections ドキュメントでも、Map は key-value pairs として説明されています。
void main() {
Map<String, int> scores = {
'Aoi': 85,
'Rin': 92,
'Sora': 78,
};
print(scores);
print(scores['Rin']);
}
この例では、キーが String、値が int です。
つまり「名前を入れると点数が分かる対応表」です。
8-2. List と Map の違い
ここはとても大切です。
Listは順番つきの並び。Mapは対応表。
たとえば、クラスの出席番号順に並べたいなら List が向いています。
一方で、「名前から点数を引きたい」なら Map が向いています。
void main() {
List<String> names = ['Aoi', 'Rin', 'Sora'];
Map<String, int> scoreMap = {
'Aoi': 85,
'Rin': 92,
'Sora': 78,
};
print(names[1]); // 順番で取り出す
print(scoreMap['Rin']); // キーで取り出す
}
初心者が飽きずに理解するコツは、「名簿なら List」「辞書なら Map」と覚えることです。
8-3. Map の追加と更新
void main() {
Map<String, String> homeroomTeachers = {
'1-A': 'Tanaka',
'1-B': 'Suzuki',
};
homeroomTeachers['1-C'] = 'Sato';
homeroomTeachers['1-A'] = 'Yamada';
print(homeroomTeachers);
}
新しいキーを入れれば追加、同じキーへ別の値を入れれば更新になります。
9. ここまでの実践
変数、型、null safety、List、Map をまとめた小さな例です。
void main() {
String schoolName = 'Prince Academy';
int studentCount = 3;
String? subTitle = null;
List<String> members = ['Aoi', 'Rin', 'Sora'];
Map<String, int> scores = {
'Aoi': 85,
'Rin': 92,
'Sora': 78,
};
print('学校名: $schoolName');
print('人数: $studentCount');
print('メンバー: $members');
print('Rinの点数: ${scores['Rin']}');
if (subTitle != null) {
print(subTitle.length);
} else {
print('サブタイトルは未設定です');
}
}
このコードには、今学んだ要素がほぼ全部入っています。
「箱を作る」「型を決める」「複数データをまとめる」「null を安全に扱う」という流れが見えればokです。
10. 練習問題
問題1
次のコードで、name の型は何ですか。
void main() {
String name = 'Mio';
print(name);
}
問題2
次のコードの score は、型推論によって何型になりますか。
void main() {
var score = 95;
print(score);
}
問題3
次のうち、null を入れてよい型はどれですか。
StringString?int
問題4
次のコードは何を表示しますか。
void main() {
List<String> fruits = ['apple', 'banana', 'orange'];
print(fruits[1]);
}
問題5
次の Map から、'math' の値は何ですか。
void main() {
Map<String, int> scores = {
'math': 90,
'english': 82,
};
print(scores['math']);
}
問題6
次のコードで問題になる行を説明してください。
void main() {
String? nickname = null;
print(nickname.length);
}
問題7
自分の言葉で、List と Map の違いを一文ずつ説明してみてください。
11. 練習問題の答え
答え1
String 型です。
文字列を入れる箱です。
答え2
int 型です。95 は整数なので、型推論によって score は int とみなされます。
答え3
正解は **2. **String? です。? が付くと nullable 型になり、null を入れられます。
答え4
banana です。
List は 0 番から始まるので、fruits[1] は2番目の要素です。
答え5
90 です。
キー 'math' に対応する値を取り出しています。
答え6
nickname は String? なので null の可能性があります。
そのため、null かもしれない状態で .length を呼ぶのは危険です。
まず nickname != null のように確認してから使う必要があります。
答え7
例です。
- List は、順番つきで値を並べて持つ型です。
- Map は、キーと値の対応で持つ型です。
12. まとめ
この節では、Dart の「データを持つ」基礎を学びました。
変数は値を入れる箱です。
型は、その箱に何を入れてよいかを決めるルールです。
Dart は type safe な言語であり、型推論も使えます。
さらに sound null safety により、null によるエラーを減らしやすくしています。List は順番つきの集まり、Map は対応表です。これらはこの後の条件分岐、ループ、関数を書くための土台になります。
歴史的に見ると、2011年の Dart 公開、2018年の Dart 2、2021年の sound null safety、2023年の Dart 3 という流れの中で、Dart は「書きやすさ」だけでなく「安全に書けること」をどんどん強めてきました。だから、今 Dart を学ぶことは、単に文法を覚えることではなく、安全で整理しやすいプログラムの考え方 を学ぶことでもあります。
参考文献
- https://dart.dev/overview
- https://dart.dev/null-safety
- https://dart.dev/language/collections
- https://dart.dev/resources/language/evolution
- https://blog.chromium.org/2011/10/dart-language-for-structured.html
- https://blog.dart.dev/announcing-dart-2-optimized-for-client-side-development-80ba01f43b6
- https://blog.dart.dev/announcing-dart-2-12-499a6e689c87
- https://blog.dart.dev/announcing-dart-3-53f065a10635