【Flutter/Dart】基本構文を復習!変数や定数、dynamicの使い方

この記事からわかること
- Flutter/Dartの基本構文
- 変数の使い方
- 厳格な値の型を扱う上での注意点
- タプルと配列の違い
- オプショナル型とは?
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Koala
- Xcode:16.0
- Flutter:3.29.2
- Dart:3.7.2
- Mac M1:Sonoma 14.6.1
Dartを学び出した私ですが、他のプログラミング言語と構文や変数の使い方が混じらないように整理しながらまとめていきたいと思います。
テスト環境:DartPad
Dartのコードの動作をサクッと試したい場合は公式が提供しているプレイプレイグラウンド「DartPad」がおすすめです。ブラウザで実行することができるのでインストールなどの手順を踏まずとも利用可能です。

末尾のセミコロン(;)が必要な言語
Dartはコードの末尾にセミコロン(;
)が必要な言語になります。つけ忘れるとコンパイル時にError: Expected ';' after this.
というエラーを吐くので注意してください。
void main() {
for (var i = 0; i < 10; i++) {
print('hello ${i + 1}'); // ここに;がないとエラーになる
} // ここに;がなくてもOK
} // ここに;がなくてもOK
また全ての末尾に付与するわけではなく、「変数の定義」や「関数の呼び出し時」に必要で、「クラスや関数の定義」の際は不要になります。
Dartの変数/定数の宣言方法
Dartは基本的に「静的型付け言語」になります。「静的型付け言語」とは変数を宣言する際にデータ型を記述する必要のある言語のことです。iOSのSwiftやAndroidのKotlinも同じく「静的型付け言語」になります。
変数の定義
変数を定義するにはデータ型 変数名 = リテラル
形式で記述します。
String message = "Hello Dart!";
// 変数なので書き換え可能
message = "Hello World!";
var
キーワードを使用することで型の記述を省略(型推論)することも可能です。この場合は値の代入時に変数の型が確定するのでその後に別の型を入れようとするとエラーになります。
var message = "Hello Dart!";
// Error: A value of type 'int' can't be assigned to a variable of type 'String'.
message = 2;
定数の定義
定数を定義する場合はfinal
キーワードを使用します。
final String endpoint = "https://appdev-room.com/";
// 定数なので書き換え不可
// Error: Can't assign to the final variable 'endpoint'.
endpoint = "https://appdev-room.com/flutter-dart-basic-syntax";
同じ定数の定義にconst
キーワードを使用する方法もあります。final
キーワードとの違いは値が確定するタイミングでfinal
は実行時(=コンストラクタで変更可能)、const
はコンパイル時(=コンストラクタで変更不可能)となっています。
const pi = 3.14;
動的型付け言語
ただDartに限ってはdynamic
型を使用することで「動的型付け言語」として動作することも可能になっています。これにより以下のように途中で異なるデータ型を格納してもエラーになることはありません。
dynamic message = "Hello Dart!";
message = 2;
Dartのデータ型の種類
データ型 | 説明 |
---|---|
int |
整数型(※) |
double |
浮動小数点数型 |
num |
int と double の両方を扱えるデータ型 |
String |
文字列型 |
bool |
真偽値型 |
dynamic |
型の制約なし |
※整数型に関してはSwiftやKotlinでは「データ長」と「符号の有無」ごとに用意されていますがDartの場合は用意されておらず、一律で「64ビット(一応環境依存)の符号あり」のようです。
Nullable型
DartではNull Safetyが導入されておりnull
を許容するかどうかを?
で指定できます。
int? number; // null を許可
print(number); // null
Nullable
型のデータを取得する際にnull
の場合にデフォルト値を取得したい場合は??
演算子を使用することで代わりの値を設定できます。
int? number;
int result = number ?? 10; // number が null の場合 10 を代入
print(result); // 10
他にもアンラップなどの基本的な使い方はSwiftと同じなのでこちらを参考にすると良いかもしれません。
コレクション型
配列や辞書型(連想配列)などはコレクション型と呼ばれます。
データ型 | 説明 |
---|---|
List |
配列を表すデータ型(リスト) |
Map |
キーと値のペアを持つデータ型 |
Set |
重複のない集合を表すデータ型 |
List
Listは配列のようなデータ構造。順序を保持し、重複も許可。
List<int> numbers = [1, 2, 3, 4, 5];
Map
Mapはキーと値のペアを管理するデータ構造。キーは一意で、順序は保証されない。
Map<String, int> scores = {
"Tanaka": 90,
"Satou": 85,
"Yoshida": 88
};
Set
Setも配列のようなデータ構造。順序は保証されず、重複も許可しない。
Set<String> fruits = {"Apple", "Banana", "Orange"};
List(配列)の使い方
一番よく使うであろうList
型の使い方を確認していきます。まず変数に格納する際は以下のように[]
で値を囲う形で記述します。
List<int> numbers = [1, 2, 3, 4, 5];
// 型を明示的に指定しなくてもOK
List strs = ["1", "2", "3", "4", "5"];
// 空の配列を生成
List<String> emptyList = [];
dynamic
型を使用することで異なるデータ型でも同じ配列で保持させることも可能です。
// 異なるデータ型でもOK
List anyTypes = [1, 2, "3", "4", "5"];
// 上記は以下と同義
List<dynamic> anyTypes = [1, 2, "3", "4", "5"];
要素を追加する
要素を追加する場合はadd
やinsert
を使用します。
List<String> fruits = ['Apple', 'Banana'];
// 要素を追加
fruits.add('Orange'); // 末尾に追加
print(fruits); // [Apple, Banana, Orange]
fruits.insert(1, 'Grapes'); // 指定位置に追加
print(fruits); // [Apple, Grapes, Banana, Orange]
// 複数の要素を追加
fruits.addAll(['Mango', 'Peach']);
print(fruits); // [Apple, Grapes, Banana, Orange, Mango, Peach]
要素を削除する
要素を削除する場合はremove
やremoveAt
を使用します。
// 要素を削除
fruits.remove('Banana'); // 指定の要素を削除
print(fruits); // [Apple, Grapes, Orange, Mango, Peach]
fruits.removeAt(2); // インデックスの要素を削除
print(fruits); // [Apple, Grapes, Mango, Peach]
fruits.clear(); // 全要素削除
print(fruits); // []
要素を取得する
要素を取得する場合は[Index番号]
でアクセスできlength
で要素数を取得できます。存在しないインデックスを指定するとRangeError
を吐きます。
List<int> numbers = [10, 20, 30, 40, 50];
// インデックスでアクセス
print(numbers[0]); // 10
print(numbers[3]); // 40
// インデックスで値を更新
numbers[1] = 25;
print(numbers); // [10, 25, 30, 40, 50]
// 長さを取得
print(numbers.length); // 5
// 存在しないインデックスを指定するとエラー
// Uncaught Error, error: Error: RangeError (index): Index out of range: index should be less than 5: 8
print(numbers[10]); // 10
関数
DartではreturnType functionName(parameters) {}
形式で関数を定義します。呼び出す時はfunctionName()
形式で記述します。
// 戻り値のある関数
int add(int a, int b) {
return a + b;
}
// 実行する
int result = add(3, 5);
print(result); // 8
// 戻り値がない場合はvoid
void greet() {
print("こんにちは!");
}
greet(); // こんにちは!
引数を{}
で囲むと名前付き引数になり、呼び出し時に未指定の場合初期値が使用されるようになります。引数の指定を必須にしたい場合はrequired
を付与します。
void introduce({String name = "匿名", int age = 0}) {
print("名前: $name, 年齢: $age");
}
introduce(name: "太郎", age: 25); // 名前: 太郎, 年齢: 25
introduce(); // 名前: 匿名, 年齢: 0
// requiredでnameの指定が必須になる
void introduce({required String name, int age = 0}) {
print("名前: $name, 年齢: $age");
}
条件分岐
続いて条件分岐処理をまとめていきます。
if文
int num = 10;
if (num > 10) {
print("num は 10 より大きい");
} else if (num == 10) {
print("num は 10 ちょうど");
} else {
print("num は 10 未満");
}
switch文
String fruit = "apple";
switch (fruit) {
case "apple":
print("リンゴです");
break;
case "banana":
print("バナナです");
break;
default:
print("その他の果物です");
}
三項演算子 (?:)
int a = 5;
int b = 10;
String result = (a > b) ? "a は b より大きい" : "a は b 以下";
print(result);
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。