Dart言語 チートシート

cheatsheet

目的別のDart構文リファレンス

1. 変数とデータ型 🔢

プログラムで扱うデータを格納するための基本的な要素です。

キーワード説明コード例
var型推論を用いて変数を宣言。再代入可能。
var name = 'Dart'; // String型と推論される
name = 'Flutter'; // 再代入可能
// name = 123; // エラー: 型が違う
final一度だけ代入可能な変数を宣言。実行時に値が決定される。型推論も可能。
final String nickname = 'Dartisan';
final creationDate = DateTime.now(); // 実行時に決定
// nickname = 'Newbie'; // エラー: 再代入不可
constコンパイル時定数を宣言。コンパイル時に値が決定される必要がある。暗黙的にfinal
const double pi = 3.14159;
const appName = 'MyApp';
// const currentTime = DateTime.now(); // エラー: コンパイル時定数ではない
[型名]明示的に型を指定して変数を宣言。再代入可能。
String language = 'Dart';
int version = 3;
language = 'Java'; // 再代入可能
説明コード例
int整数値を表す型。プラットフォームによってサイズが異なる。Webでは64bit浮動小数点数として扱われる場合がある。
int count = 10;
int hexValue = 0xFF; // 16進数
double浮動小数点数を表す型。IEEE 754 標準の64bit倍精度。
double price = 99.99;
double exponent = 1.42e5; // 指数表記
numintdoubleのスーパータイプ。両方の型を受け入れ可能。
num value1 = 10;    // int
num value2 = 10.5;  // double
value1 += 0.5;    // value1 は double になる
bool真偽値を表す型。trueまたはfalseのみ。
bool isLoading = true;
bool isCompleted = false;
String文字列を表す型。UTF-16コードユニットのシーケンス。シングルクォート(')またはダブルクォート(")で囲む。
String single = 'Hello';
String doubleQ = "World";
String multiLine = '''
This is a
multi-line string.
''';
String raw = r'Raw string \n no escape'; // rプレフィックスでraw文字列
String interpolation = 'Value: $count'; // 文字列補間
String expression = 'Total: ${price * count}'; // 式の埋め込み

Dart 2.12から導入された、Null参照によるエラーをコンパイル時に防ぐ仕組み。

記号/キーワード説明コード例
? (Nullable型)型名の後に付けることで、その変数がnullを許容することを示す。
String? nullableName = 'Alice';
nullableName = null; // OK
int? age; // 初期値は null
! (Nullチェック演算子)Nullable型の変数がnullでないことをコンパイラに表明する。もしnullだった場合は実行時エラー。
int definiteAge = age!; // ageがnullでないと確信している場合
// 注意: ageがnullだと実行時エラー
late変数の初期化を遅延させることを示す。宣言時には初期化せず、最初のアクセスまでに初期化されることを保証。finalと併用可能。
late String description;
void initialize() {
  description = 'Initialized later';
}
// 使用前に initialize() を呼ぶ必要がある

late final String apiData = fetchApiData(); // 初期化を一度だけ遅延
required名前付きパラメータが必須であることを示す。Null Safety以前の@requiredアノテーションに代わるもの。
void printDetails({required String name, int? age}) {
  print('Name: $name, Age: ${age ?? 'Unknown'}');
}
// 呼び出し時: printDetails(name: 'Bob');

複数の値をまとめて扱うための型。

List (リスト)

順序付けられた要素のコレクション。インデックスでアクセス可能。デフォルトは可変長。

操作コード例
リテラルでの作成
// 型推論
var list1 = [1, 2, 3];
// 型指定
List<String> list2 = ['apple', 'banana'];
// const リスト (要素も不変)
var constList = const [10, 20];
// 空リスト
var emptyList = <int>[];
要素へのアクセス
print(list1[0]); // 1
print(list2.length); // 2
print(list1.first); // 1
print(list1.last); // 3
要素の追加・削除
list1.add(4); // [1, 2, 3, 4]
list2.insert(1, 'orange'); // ['apple', 'orange', 'banana']
list1.remove(2); // [1, 3, 4]
list2.removeAt(0); // ['orange', 'banana']
list1.clear(); // []
イテレーション
for (var item in list2) {
  print(item);
}
list1.forEach((n) => print(n));
スプレッド演算子
var list3 = [0, ...list1, 5]; // list1の要素を展開
var list4 = [0, ...?list1, 5]; // list1がnullなら無視
Collection if / for
bool includeZero = true;
var list5 = [
  if (includeZero) 0, // 条件がtrueなら要素を追加
  for (var i = 1; i < 4; i++) i, // ループで要素を追加
]; // [0, 1, 2, 3] (includeZeroがtrueの場合)

Set (セット)

順序のない、一意な要素のコレクション。

操作コード例
リテラルでの作成
// 型推論
var set1 = {'a', 'b', 'c', 'a'}; // {'a', 'b', 'c'} 重複は無視
// 型指定
Set<int> set2 = {1, 2, 3};
// const セット
var constSet = const {10, 20};
// 空セット (Mapリテラルと区別するため型指定が必要)
var emptySet1 = <String>{};
var emptySet2 = {}; // これは空のMapになる
要素の確認・追加・削除
print(set1.contains('b')); // true
set2.add(4); // {1, 2, 3, 4}
set2.add(1); // 変化なし
set1.remove('a'); // {'b', 'c'}
集合演算
var s1 = {1, 2, 3};
var s2 = {3, 4, 5};
print(s1.union(s2)); // {1, 2, 3, 4, 5} (和集合)
print(s1.intersection(s2)); // {3} (積集合)
print(s1.difference(s2)); // {1, 2} (差集合 s1 - s2)

Map (マップ)

キーと値のペアのコレクション。キーは一意である必要がある。

操作コード例
リテラルでの作成
// 型推論 (キー: String, 値: dynamic)
var map1 = {
  'name': 'Dart',
  'year': 2011,
};
// 型指定
Map<String, int> map2 = {
  'apple': 100,
  'banana': 150,
};
// const マップ
var constMap = const {'id': 1, 'status': 'active'};
// 空マップ
var emptyMap = <String, double>{};
要素へのアクセス
print(map1['name']); // Dart
print(map2['orange']); // null (キーが存在しない場合)
print(map1.length); // 2
print(map2.containsKey('apple')); // true
print(map1.containsValue(2011)); // true
要素の追加・更新・削除
// 追加 or 更新
map1['creator'] = 'Google';
map2['apple'] = 120; // 更新
// 指定キーがなければ追加、あれば何もしない
map1.putIfAbsent('version', () => 3);
// 削除
map2.remove('banana');
map1.clear(); // 空にする
イテレーション
map2.forEach((key, value) {
  print('$key: $value');
});

for (var key in map1.keys) {
  print(key);
}
for (var value in map1.values) {
  print(value);
}
for (var entry in map1.entries) {
  print('${entry.key}: ${entry.value}');
}
説明コード例
dynamic動的な型。型チェックが実行時に行われる。型安全性が低下するため、使用は慎重に。
dynamic flexible = 'hello';
flexible = 123; // OK
flexible.someMethod(); // コンパイルエラーにはならないが、実行時エラーの可能性
ObjectDartの全てのクラスのルートクラス(Nullを除く、Null Safety有効下)。dynamicと違い、メソッド呼び出しには型キャストが必要な場合がある。
Object obj = 'A string';
// print(obj.length); // エラー: Objectにlengthはない
if (obj is String) {
  print(obj.length); // キャストされる
}
Runes文字列のUTF-32コードポイント(Unicode文字)を表現する。絵文字や特殊文字の扱いに。
var clapping = '\u{1F44F}'; // 👏
print(clapping);
Runes input = Runes('I ❤️ Dart');
print(String.fromCharCodes(input)); // I ❤️ Dart
SymbolDartプログラムで宣言された演算子や識別子を表すオブジェクト。リフレクションやメタプログラミングで使用されることがあるが、一般的ではない。
Symbol lib = #dart.core;
print(lib); // Symbol("dart.core")

2. 制御フロー 🔀

プログラムの実行順序を制御するための構文。

構文説明コード例
if / else if / else条件に基づいて処理を分岐させる。
int score = 85;
if (score >= 90) {
  print('A');
} else if (score >= 80) {
  print('B'); // これが実行される
} else {
  print('C');
}
for ループ指定された回数、または条件が満たされる間、処理を繰り返す。
// 基本的なforループ
for (int i = 0; i < 3; i++) {
  print(i); // 0, 1, 2
}

// for-in ループ (コレクションの要素を反復)
var numbers = [10, 20, 30];
for (var n in numbers) {
  print(n); // 10, 20, 30
}
while ループ条件が真である間、処理を繰り返す。最初に条件を評価。
int count = 0;
while (count < 3) {
  print('While: $count'); // 0, 1, 2
  count++;
}
do-while ループ処理を一度実行してから、条件が真である間、処理を繰り返す。最後に条件を評価。
int value = 0;
do {
  print('Do-While: $value'); // 0, 1, 2
  value++;
} while (value < 3);

// 条件が最初から偽でも最低1回は実行される
int anotherValue = 5;
do {
 print('Executed once'); // これが実行される
} while (anotherValue < 3);
switch / case特定の値に基づいて処理を分岐させる。int, String, コンパイル時定数で利用可能。Dart 3.0以降はより強力なパターンマッチングが可能。
String command = 'OPEN';
switch (command) {
  case 'OPEN':
    print('Opening...');
    break; // breakが必須 (フォールスルーしない)
  case 'CLOSED':
    print('Closing...');
    break;
  default: // どのcaseにも一致しない場合
    print('Unknown command');
}

// 空のcaseはフォールスルー可能
int number = 1;
switch (number) {
  case 0:
  case 1:
    print('Zero or One'); // これが実行される
    break;
  case 2:
    print('Two');
    break;
}
break現在のループ(for, while, do-while)またはswitch文を終了させる。
for (int i = 0; i < 10; i++) {
  if (i == 5) {
    break; // iが5になったらループを抜ける
  }
  print(i); // 0, 1, 2, 3, 4
}
continue現在のループの残りの処理をスキップし、次のイテレーションに進む。
for (int i = 0; i < 5; i++) {
  if (i % 2 == 0) {
    continue; // 偶数の場合は下のprintをスキップ
  }
  print('Odd: $i'); // Odd: 1, Odd: 3
}
assert開発中に条件が真であることを表明する。Flutterのデバッグモードやdart --enable-assertsで実行した場合のみ有効。本番ビルドでは無視される。
var text = 'hello';
assert(text != null); // textがnullでないことを確認

var number = -5;
// 条件が偽の場合、AssertionErrorが発生 (第2引数にメッセージ指定可能)
assert(number >= 0, 'Number must be non-negative');

3. 関数 ⚙️

特定のタスクを実行するコードのまとまり。

形式説明コード例
基本形戻り値の型、関数名、パラメータリスト、関数本体で構成される。戻り値がない場合はvoid
// 戻り値あり
int add(int a, int b) {
  return a + b;
}

// 戻り値なし
void printMessage(String message) {
  print(message);
}

// 呼び出し
int result = add(5, 3); // result は 8
printMessage('Hello Dart!');
アロー構文 (=>)関数本体が一つの式のみの場合に使える短縮記法。{ return 式; } と同等。
int multiply(int a, int b) => a * b;

void log(String msg) => print('[LOG] $msg');

// 呼び出し
int product = multiply(4, 5); // product は 20
log('Process started.');
戻り値の型省略戻り値の型を省略するとdynamicとして扱われるが、明示することが推奨される。
greet(String name) { // dynamic greet(String name) と同じ
  return 'Hi, $name!';
}

関数に渡す値。

種類説明コード例
必須位置パラメータ最も基本的なパラメータ。定義された順序で値を渡す必要があり、省略不可。
void printInfo(String name, int age) {
  print('$name is $age years old.');
}
// 呼び出し
printInfo('Alice', 30);
名前付きパラメータ{ }で囲み、呼び出し時にパラメータ名を指定する。順序は任意。デフォルトでオプショナル(Null Safety下では?requiredかデフォルト値が必要)。
void enableFlags({bool? bold, bool? hidden}) {
  print('Bold: ${bold ?? false}, Hidden: ${hidden ?? false}');
}
// 呼び出し (順序任意、一部省略可)
enableFlags(hidden: true); // Bold: false, Hidden: true
enableFlags(bold: true, hidden: false); // Bold: true, Hidden: false

// required を使った必須の名前付きパラメータ
void setup({required String url, int port = 80}) {
  print('Setup $url on port $port');
}
setup(url: 'example.com'); // Setup example.com on port 80
// setup(port: 8080); // エラー: url is required
オプション位置パラメータ[ ]で囲み、呼び出し時に省略可能。定義順に値を渡す。デフォルト値も設定可能。
String say(String from, String msg, [String? device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result on a $device';
  }
  return result;
}
// 呼び出し
print(say('Bob', 'Hello')); // Bob says Hello
print(say('Charlie', 'Hi', 'Laptop')); // Charlie says Hi on a Laptop

// デフォルト値付き
void configure(String setting, [int level = 1]) {
   print('Setting: $setting, Level: $level');
}
configure('Mode'); // Setting: Mode, Level: 1
configure('Mode', 5); // Setting: Mode, Level: 5
デフォルトパラメータ値名前付きパラメータとオプション位置パラメータには=を使ってデフォルト値を設定できる。デフォルト値はコンパイル時定数である必要がある。
// 名前付きパラメータのデフォルト値
void setConfig({String theme = 'light', int timeout = 5000}) {
  print('Theme: $theme, Timeout: $timeout');
}
setConfig(); // Theme: light, Timeout: 5000
setConfig(theme: 'dark'); // Theme: dark, Timeout: 5000

// オプション位置パラメータのデフォルト値 (前述)
void config([int level = 1]) {/*...*/}

名前を持たない関数。変数に代入したり、他の関数に引数として渡したりできる。

void main() {
  // 変数に関数を代入
  var loudify = (String msg) => '!!! ${msg.toUpperCase()} !!!';
  print(loudify('hello')); // !!! HELLO !!!

  // リストの各要素に適用
  var numbers = [1, 2, 3];
  numbers.forEach((number) {
    print('Number: $number');
  });

  // 引数として渡す
  List<int> performOperation(List<int> list, int Function(int) action) {
    return list.map(action).toList();
  }
  var doubled = performOperation(numbers, (x) => x * 2);
  print(doubled); // [2, 4, 6]
}

関数を引数として受け取るか、関数を戻り値として返す関数。

// 関数を引数として受け取る (例: forEach, map, where)
var numbers = [1, 2, 3, 4, 5];
numbers.where((n) => n % 2 == 0) // 偶数のみフィルタリング (関数を渡す)
       .forEach(print); // 各要素を出力 (関数を渡す) -> 2, 4

// 関数を返す関数
Function makeAdder(int addBy) {
  return (int i) => addBy + i;
}

void main() {
  var add2 = makeAdder(2); // addBy=2 の関数を生成
  var add4 = makeAdder(4); // addBy=4 の関数を生成

  print(add2(3)); // 5 (2 + 3)
  print(add4(3)); // 7 (4 + 3)
}

一連の値を遅延して生成する関数。sync* (同期) または async* (非同期) と yield を使う。

種類説明コード例
sync* / yield同期的に値のシーケンス (Iterable) を生成する。yieldで値を一つずつ返す。
Iterable<int> countFrom(int n) sync* {
  int k = n;
  while (k >= 0) {
    yield k--; // 値を返す (関数は一時停止)
  }
}

void main() {
  // countFrom(3) を呼び出してもすぐには実行されない
  var sequence = countFrom(3);
  print('Generated Iterable');
  // イテレートする時に初めて実行される
  for (var value in sequence) {
    print(value); // 3, 2, 1, 0
  }
}
async* / yield非同期的に値のシーケンス (Stream) を生成する。イベントやデータの流れを表現するのに使う。
Stream<int> asyncCountDown(int n) async* {
  for (int i = n; i >= 0; i--) {
    await Future.delayed(Duration(milliseconds: 500));
    yield i; // Streamに値を流す
  }
}

void main() async {
  print('Starting countdown...');
  // Streamをlistenして値を受け取る
  await for (var value in asyncCountDown(3)) {
    print(value); // 0.5秒ごとに 3, 2, 1, 0 と出力
  }
  print('Countdown finished!');
}

4. 演算子 ➕➖✖️➗

値に対して操作を行うための記号。

種類演算子説明・コード例
算術演算子+加算: 5 + 2 // 7
-減算: 5 - 2 // 3
-expr単項マイナス: -5
*乗算: 5 * 2 // 10
/除算 (常にdoubleを返す): 5 / 2 // 2.5
~/整数除算 (結果を整数にする): 5 ~/ 2 // 2
%剰余 (余り): 5 % 2 // 1
比較演算子==等価: 5 == 5 // true
!=非等価: 5 != 2 // true
>より大きい: 5 > 2 // true
<より小さい: 5 < 2 // false
>=以上: 5 >= 5 // true
<=以下: 5 <= 2 // false
論理演算子!expr論理否定 (NOT): !true // false
||論理和 (OR): true || false // true
&&論理積 (AND): true && false // false
代入演算子=代入: int a = 5;
+=加算代入: a += 2; // a = a + 2
-=減算代入: a -= 1; // a = a - 1
*=乗算代入: a *= 3; // a = a * 3
/=除算代入: double b = 6; b /= 2; // b = b / 2 (bは3.0)
~/=整数除算代入: a ~/= 2; // a = a ~/ 2
%=剰余代入: a %= 3; // a = a % 3
Null関連演算子?? (Null合体演算子)左辺がnullの場合に右辺の値を返す: String? name; String displayName = name ?? 'Guest'; // displayName は 'Guest'
??= (Null合体代入演算子)左辺がnullの場合のみ右辺の値を代入: int? score; score ??= 0; // score は 0 になる
?. (Null Awareアクセス)左辺がnullでない場合にのみ右辺のプロパティやメソッドにアクセス。nullの場合はnullを返す: String? message; int? len = message?.length; // len は null
型テスト演算子isオブジェクトが指定した型であるかチェック: if (obj is String) { ... }
is!オブジェクトが指定した型でないかチェック: if (obj is! int) { ... }
ビット演算子&ビットAND: 5 & 1 // 1 (0101 & 0001 = 0001)
|ビットOR: 5 | 1 // 5 (0101 | 0001 = 0101)
^ビットXOR: 5 ^ 1 // 4 (0101 ^ 0001 = 0100)
~exprビットNOT (ビット反転): ~5 // -6 (プラットフォーム依存)
<<左シフト: 5 << 1 // 10 (0101 << 1 = 1010)
>>右シフト: 5 >> 1 // 2 (0101 >> 1 = 0010)
>>>符号なし右シフト: Dart 3.0以降
カスケード記法..同一オブジェクトに対して連続してメソッド呼び出しやプロパティ設定を行う:
var paint = Paint()
  ..color = Colors.blue
  ..strokeWidth = 5.0
  ..style = PaintingStyle.stroke;
// 上記は以下と同等
// var paint = Paint();
// paint.color = Colors.blue;
// paint.strokeWidth = 5.0;
// paint.style = PaintingStyle.stroke;
スプレッド演算子...コレクション(List, Set, Map)の要素を展開して別のコレクションに挿入: var list1 = [1, 2]; var list2 = [0, ...list1, 3]; // [0, 1, 2, 3]
...? (Null Aware)元のコレクションがnullの場合、展開をスキップ: List<int>? list3; var list4 = [0, ...?list3, 4]; // [0, 4]
条件式 (三項演算子)condition ? expr1 : expr2conditiontrueならexpr1falseならexpr2を評価: int points = 10; String rank = points > 5 ? 'High' : 'Low'; // rank は 'High'

5. クラスとオブジェクト 🏛️

オブジェクト指向プログラミングの基本。データと振る舞いをまとめた設計図(クラス)と、その実体(オブジェクト)。

class Point {
  // インスタンス変数 (フィールド)
  double x = 0; // 初期値を設定
  double y = 0;

  // コンストラクタ (クラス名と同じ名前のメソッド)
  Point(double initialX, double initialY) {
    x = initialX;
    y = initialY;
  }

  // メソッド (振る舞い)
  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy); // sqrt は dart:math から import 必要
  }
}

void main() {
  // インスタンス化 (オブジェクトの生成)
  var p1 = Point(3, 4);
  var p2 = Point(0, 0);

  // プロパティへのアクセス
  print('p1.x: ${p1.x}'); // 3.0

  // メソッドの呼び出し
  double dist = p1.distanceTo(p2);
  print('Distance: $dist'); // 5.0
}

オブジェクト生成時に初期化を行うための特別なメソッド。

種類説明コード例
デフォルトコンストラクタクラス名と同じ名前。引数を受け取り、フィールドを初期化。糖衣構文 (this.fieldName) が使える。
class Rectangle {
  double width, height;

  // 糖衣構文を使ったコンストラクタ
  Rectangle(this.width, this.height);

  // 通常の書き方 (上記と同じ意味)
  // Rectangle(double width, double height) {
  //   this.width = width;
  //   this.height = height;
  // }
}
名前付きコンストラクタClassName.identifierName() の形式。複数のコンストラクタを定義したい場合や、特定の目的の初期化を行いたい場合に使う。
class Circle {
  double radius;
  static const double pi = 3.14159;

  // デフォルトコンストラクタ
  Circle(this.radius);

  // 名前付きコンストラクタ: 直径から生成
  Circle.fromDiameter(double diameter) : radius = diameter / 2;

  // 名前付きコンストラクタ: 単位円
  Circle.unit() : radius = 1.0;

  double get area => pi * radius * radius;
}

// 呼び出し
var c1 = Circle(5);
var c2 = Circle.fromDiameter(10); // c1と同じ半径
var c3 = Circle.unit();
ファクトリコンストラクタfactoryキーワードを使用。必ずしも新しいインスタンスを生成するとは限らない。キャッシュされたインスタンスを返したり、サブクラスのインスタンスを返したりできる。
class Logger {
  final String name;
  bool _mute = false; // プライベート変数

  // キャッシュ用Map (クラス外部からはアクセス不可)
  static final Map<String, Logger> _cache = <String, Logger>{};

  // ファクトリコンストラクタ
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  // プライベートな名前付きコンストラクタ
  Logger._internal(this.name);

  void log(String msg) {
    if (!_mute) print('$name: $msg');
  }
}

// 呼び出し
var logger1 = Logger('UI'); // 新しいインスタンス or キャッシュから取得
var logger2 = Logger('UI'); // logger1と同じインスタンスを返す
print(identical(logger1, logger2)); // true
定数コンストラクタconstキーワードを使用。全てのインスタンス変数がfinalである必要があり、コンパイル時定数としてオブジェクトを生成できる。パフォーマンス向上に繋がる。
class ImmutablePoint {
  final double x;
  final double y;

  // 定数コンストラクタ
  const ImmutablePoint(this.x, this.y);
}

// 呼び出し
var p1 = const ImmutablePoint(1, 1);
var p2 = const ImmutablePoint(1, 1);
// 同じ引数でconstコンストラクタを呼ぶと、同一インスタンスが返される
print(identical(p1, p2)); // true

var p3 = ImmutablePoint(2, 2); // constなしだと通常のインスタンス
var p4 = ImmutablePoint(2, 2);
print(identical(p3, p4)); // false
リダイレクトコンストラクタコンストラクタ本体を持たず、: this(...) または : super(...) のように、同じクラスの別のコンストラクタやスーパークラスのコンストラクタに処理を委譲する。
class Square extends Rectangle {
  // スーパークラス(Rectangle)のコンストラクタを呼び出す
  Square(double size) : super(size, size);

  // 同じクラスの別のコンストラクタに委譲
  Square.unit() : this(1.0);
}
初期化子リストコンストラクタの:の後に記述し、super()の呼び出しやfinal変数の初期化を行う。コンストラクタ本体が実行される前に実行される。
import 'dart:math';

class Point3D {
  final double x, y, z;
  final double magnitude; // 計算結果を格納するfinal変数

  // 初期化子リストで magnitude を計算・初期化
  Point3D(this.x, this.y, this.z)
      : magnitude = sqrt(x * x + y * y + z * z) {
    print('Point3D constructor body'); // 初期化子リストの後で実行
  }
}

インスタンス変数へのアクセスを制御するための特別なメソッド。getsetキーワードを使う。

class Temperature {
  double celsius;

  Temperature(this.celsius);

  // ゲッター: ファーレンハイト度を計算して返す
  double get fahrenheit => celsius * 1.8 + 32;

  // セッター: ファーレンハイト度からセルシウス度を設定
  set fahrenheit(double value) => celsius = (value - 32) / 1.8;
}

void main() {
  var temp = Temperature(25); // セルシウス度で初期化

  // ゲッター呼び出し (メソッド呼び出しのように () は不要)
  print('${temp.celsius}°C is ${temp.fahrenheit}°F'); // 25.0°C is 77.0°F

  // セッター呼び出し (代入のように使う)
  temp.fahrenheit = 86;
  print('Now it is ${temp.celsius}°C'); // Now it is 30.0°C
}

既存のクラス(スーパークラス)のプロパティとメソッドを引き継いで新しいクラス(サブクラス)を作成する仕組み。コードの再利用性を高める。Dartは単一継承。

// スーパークラス
class Vehicle {
  String model;
  int year;

  Vehicle(this.model, this.year);

  void honk() {
    print('Beep beep!');
  }
}

// サブクラス (Vehicleを継承)
class Car extends Vehicle {
  int numberOfDoors;

  // スーパークラスのコンストラクタを呼び出す (superを使用)
  Car(String model, int year, this.numberOfDoors) : super(model, year);

  // メソッドのオーバーライド (@overrideアノテーション推奨)
  @override
  void honk() {
    print('Honk honk!'); // 車固有の音に変更
  }

  void drive() {
    print('$model is driving...');
  }
}

void main() {
  var myCar = Car('Tesla Model 3', 2023, 4);
  print(myCar.model); // Tesla Model 3 (継承したプロパティ)
  myCar.honk(); // Honk honk! (オーバーライドしたメソッド)
  myCar.drive(); // Tesla Model 3 is driving... (Car固有のメソッド)
}

インスタンス化できないクラス。サブクラスで実装されるべきメソッド(抽象メソッド)のシグネチャを定義するためなどに使う。インターフェースとしても機能する。

abstract class Shape {
  // 抽象メソッド (本体を持たない)
  double get area;

  // 通常のメソッドも持てる
  void printDescription() {
    print('This is a shape.');
  }
}

class Square extends Shape {
  double side;
  Square(this.side);

  // 抽象メソッドの実装が必須
  @override
  double get area => side * side;

  @override
  void printDescription() {
    print('This is a square with side $side.');
  }
}

void main() {
  // var shape = Shape(); // エラー: 抽象クラスはインスタンス化できない
  var sq = Square(5);
  print(sq.area); // 25.0
  sq.printDescription(); // This is a square with side 5.0
}

クラスが特定のメソッドやゲッター/セッターを持つことを保証する規約。Dartでは、全てのクラスが暗黙的にインターフェースを定義する。implementsキーワードでクラスがインターフェースを実装することを示す。実装するクラスは、インターフェースの全てのメンバー(メソッド、ゲッター、セッター)を実装(オーバーライド)する必要がある。

class Speaker {
  void announce(String message) {
    print('Announcing: $message');
  }
}

class Amplifier {
  void amplify(int level) {
    print('Amplifying to $level');
  }
}

// SpeakerとAmplifierの両方のインターフェースを実装するクラス
class SmartSpeaker implements Speaker, Amplifier {
  @override
  void announce(String message) {
    print('SmartSpeaker says: $message');
  }

  @override
  void amplify(int level) {
    print('SmartSpeaker volume set to $level');
  }
}

void main() {
  var smart = SmartSpeaker();
  smart.announce('Hello'); // SmartSpeaker says: Hello
  smart.amplify(8);      // SmartSpeaker volume set to 8

  // インターフェース型として扱うことも可能
  Speaker s = smart;
  s.announce('World'); // SmartSpeaker says: World
}

クラス間でコード(メソッドやフィールド)を再利用するための仕組み。継承と異なり、複数のミックスインを一つのクラスに取り込むことができる。mixinキーワードでミックスインを定義し、withキーワードでクラスに適用する。ミックスインはコンストラクタを持てない。特定のスーパータイプを要求することもできる (on キーワード)。

// ミックスイン定義
mixin Flyer {
  void fly() {
    print("I'm flying!");
  }
}

mixin Walker {
  void walk() {
    print("I'm walking!");
  }
}

// 特定のスーパータイプを要求するミックスイン
mixin Swimmer on Animal { // Animalクラスかそのサブクラスにしか適用できない
  void swim() {
    print("$name is swimming!"); // Animalクラスのnameプロパティにアクセス
  }
}

class Animal {
  String name;
  Animal(this.name);
}

// ミックスインを適用したクラス
class Bird extends Animal with Flyer, Walker {
  Bird(String name) : super(name);
}

class Duck extends Animal with Flyer, Walker, Swimmer {
  Duck(String name) : super(name);
}

// class Fish with Swimmer {} // エラー: SwimmerはAnimalを継承していないクラスには使えない

void main() {
  var bird = Bird('Sparrow');
  bird.fly();   // I'm flying!
  bird.walk();  // I'm walking!

  var duck = Duck('Donald');
  duck.fly();   // I'm flying!
  duck.walk();  // I'm walking!
  duck.swim();  // Donald is swimming!
}

既存のライブラリやクラス(自分で定義したものも含む)を変更せずに、新しいメソッドやゲッター/セッターを追加する機能。

// Stringクラスに新しいメソッドを追加する拡張
extension StringParsing on String {
  int? parseIntOrNull() {
    return int.tryParse(this);
  }

  String capitalize() {
    if (isEmpty) return this;
    return '${this[0].toUpperCase()}${substring(1)}';
  }
}

// Listクラスにゲッターを追加する拡張
extension ListUtils<T> on List<T> {
  T? get secondOrNull {
    return length >= 2 ? this[1] : null;
  }
}


void main() {
  String numberStr = '123';
  String word = 'hello';
  String invalid = 'abc';

  print(numberStr.parseIntOrNull()); // 123
  print(invalid.parseIntOrNull()); // null
  print(word.capitalize()); // Hello

  var numbers = [10, 20, 30];
  var names = ['Alice'];
  print(numbers.secondOrNull); // 20
  print(names.secondOrNull); // null
}

クラス自体に関連付けられたメンバー(変数やメソッド)。インスタンス化せずにクラス名から直接アクセスできる。

class AppConfig {
  // 静的変数 (クラス変数)
  static const String appName = 'My Cool App';
  static bool loggingEnabled = true;

  // 静的メソッド (クラスメソッド)
  static void printAppName() {
    print('App Name: $appName');
  }

  static double calculateVat(double price) {
    return price * 0.1; // 例: 10%のVAT
  }
}

void main() {
  // インスタンス化せずにアクセス
  print(AppConfig.appName); // My Cool App
  AppConfig.printAppName(); // App Name: My Cool App

  AppConfig.loggingEnabled = false; // 静的変数の変更
  print(AppConfig.loggingEnabled); // false

  double price = 100.0;
  double vat = AppConfig.calculateVat(price);
  print('VAT: $vat'); // VAT: 10.0
}

固定された数の定数値を表現するための特殊なクラス。enumキーワードで定義する。Dart 2.17以降、メソッドやフィールドを持つことも可能になった(Enhanced Enums)。

// 基本的な列挙型
enum Status {
  pending,
  running,
  completed,
  failed
}

// Enhanced Enum (メソッドとフィールドを持つ)
enum Color {
  red(0xFFF44336, '赤'),
  green(0xFF4CAF50, '緑'),
  blue(0xFF2196F3, '青'); // セミコロンが必要

  final int hexCode;
  final String japaneseName;

  // 定数コンストラクタ
  const Color(this.hexCode, this.japaneseName);

  // メソッド
  String get hexString => '#${hexCode.toRadixString(16).substring(2).toUpperCase()}';

  @override
  String toString() => 'Color($japaneseName)';
}

void main() {
  Status currentStatus = Status.running;

  // switch文での利用
  switch (currentStatus) {
    case Status.pending:
      print('Waiting to start...');
      break;
    case Status.running:
      print('In progress...'); // これが実行される
      break;
    case Status.completed:
      print('Finished successfully.');
      break;
    case Status.failed:
      print('An error occurred.');
      break;
    // default節は必須ではない (全てのenum値を網羅している場合)
  }

  // 列挙値のインデックスと名前
  print(currentStatus.index); // 1 (定義順のインデックス)
  print(currentStatus.name); // 'running' (Dart 2.15以降)

  // Enhanced Enumの使用
  Color favColor = Color.blue;
  print(favColor.japaneseName); // 青
  print(favColor.hexCode); // 4280391411 (0xFF2196F3)
  print(favColor.hexString); // #2196F3
  print(favColor); // Color(青)

  // values: 全ての列挙値をリストで取得
  print(Color.values); // [Color.red, Color.green, Color.blue]
}

6. 非同期処理 ⏳

時間のかかる処理(ネットワーク通信、ファイルI/Oなど)をメインの処理(UI更新など)をブロックせずに行うための仕組み。

非同期操作の最終的な結果(値またはエラー)を表すオブジェクト。操作が完了すると、Futureは値またはエラーで「完了」する。

import 'dart:async';

// 時間のかかる処理を模倣する関数 (Futureを返す)
Future<String> fetchData() {
  // 3秒後に 'Data fetched successfully!' という文字列を返すFutureを生成
  return Future.delayed(Duration(seconds: 3), () {
    // ここでエラーが発生する可能性もある
    // throw Exception('Failed to fetch data');
    return 'Data fetched successfully!';
  });
}

void main() {
  print('Fetching data...');
  final futureResult = fetchData();

  // Futureが完了したときの処理 (then)
  futureResult.then((result) {
    // 成功した場合の処理
    print('Success: $result'); // 3秒後に出力される
  }).catchError((error) {
    // エラーが発生した場合の処理
    print('Error: $error');
  }).whenComplete(() {
    // 成功・失敗に関わらず、完了時に必ず実行される処理
    print('Future completed.');
  });

  print('Doing other work...'); // fetchDataの完了を待たずに実行される
}

Futureをより同期的なコードのように書けるようにする糖衣構文。

  • async: 関数が非同期であり、内部でawaitを使う可能性があることを示す。この関数は暗黙的にFutureを返す。
  • await: Futureが完了するのを待つ。awaitasync関数内でのみ使用可能。
import 'dart:async';

Future<String> fetchUserData() {
  return Future.delayed(Duration(seconds: 2), () => 'User Alice');
}

Future<String> fetchUserPosts(String user) {
  return Future.delayed(Duration(seconds: 1), () => 'Posts for $user');
}

// async関数: 内部でawaitを使用
Future<void> displayUserDataAndPosts() async {
  print('Start fetching...');
  try {
    // await: fetchUserDataが完了するまで待つ
    String user = await fetchUserData();
    print('Got user: $user');

    // await: fetchUserPostsが完了するまで待つ
    String posts = await fetchUserPosts(user);
    print('Got posts: $posts');

  } catch (e) {
    print('An error occurred: $e');
  } finally {
    print('Fetching finished.');
  }
}

void main() {
  print('Main function start.');
  displayUserDataAndPosts(); // 非同期関数を呼び出す
  print('Main function end.'); // displayUserDataAndPostsの完了を待たずに実行される
}
/* 出力順序の例:
Main function start.
Start fetching...
Main function end.
(2秒後) Got user: User Alice
(さらに1秒後) Got posts: Posts for User Alice
Fetching finished.
*/

非同期的なイベント(データのシーケンス)を扱うためのオブジェクト。Futureが一つの結果を返すのに対し、Streamは複数の値やエラーを時間経過とともに生成できる。ユーザー入力、ファイルの読み込み、ネットワークからのデータ受信などに使われる。

import 'dart:async';

// 1秒ごとに数値を生成するStreamを作成する関数
Stream<int> countStream(int max) async* { // async* でStreamを返すジェネレータ関数
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i; // Streamに値を送る
    if (i == 3) {
      // エラーを送ることもできる
      // yield* Stream.error(Exception('Something went wrong at 3'));
    }
  }
}

void main() async {
  print('Starting stream...');
  Stream<int> stream = countStream(5);

  // Streamを購読 (listen) してデータを受け取る
  StreamSubscription subscription = stream.listen(
    (data) {
      // データ受信時の処理
      print('Received: $data');
    },
    onError: (error) {
      // エラー発生時の処理
      print('Error: $error');
    },
    onDone: () {
      // Streamが完了 (閉じた) ときの処理
      print('Stream is done.');
    },
    cancelOnError: false // trueにするとエラー発生時に自動で購読解除
  );

  // 5秒後に購読をキャンセルする場合
  // await Future.delayed(Duration(seconds: 5));
  // print('Cancelling subscription...');
  // await subscription.cancel();

  // await for ループを使ってStreamを処理することも可能 (async関数内)
  print('Using await for...');
  try {
    await for (var value in countStream(3)) {
      print('Await for received: $value');
    }
    print('Await for finished.');
  } catch (e) {
    print('Await for error: $e');
  }

  print('Main function continues...');
}
/* 出力例:
Starting stream...
Using await for...
Main function continues...
(1秒後) Received: 1
(1秒後) Await for received: 1
(1秒後) Received: 2
(1秒後) Await for received: 2
(1秒後) Received: 3
(1秒後) Await for received: 3
Await for finished.
(1秒後) Received: 4
(1秒後) Received: 5
Stream is done.
*/

Streamの種類:

  • Single-subscription streams: 一度に一つのリスナーしか持つことができない。データシーケンス全体が順番に配信されることを想定(例: ファイル読み込み)。
  • Broadcast streams: 複数のリスナーを持つことができる。いつでも購読開始でき、購読開始後に発生したイベントを受け取る(例: マウスイベント)。stream.asBroadcastStream()で変換可能。

Dartで並行処理(本当の意味での並列処理)を行うための仕組み。各Isolateは自身のメモリ空間とイベントループを持つ独立した実行単位。重い計算処理をバックグラウンドで行い、メインIsolate(UIを担当)をブロックさせないために使う。

Isolate間の通信はメッセージパッシング(SendPortReceivePort)で行う。

import 'dart:isolate';
import 'dart:async';

// 新しいIsolateで実行される関数 (トップレベル関数またはstaticメソッドである必要あり)
void heavyComputation(SendPort sendPort) {
  print('[Isolate] Starting computation...');
  int result = 0;
  for (int i = 0; i < 1000000000; i++) { // 重い計算の例
    result += 1;
  }
  print('[Isolate] Computation finished.');
  // 計算結果をメインIsolateに送信
  sendPort.send(result);
}

Future<void> runComputationInIsolate() async {
  print('[Main] Creating ReceivePort...');
  // メインIsolateでメッセージを受け取るためのポート
  final receivePort = ReceivePort();

  print('[Main] Spawning Isolate...');
  // Isolateを生成し、実行する関数と通信用のSendPortを渡す
  final isolate = await Isolate.spawn(heavyComputation, receivePort.sendPort);

  print('[Main] Waiting for result from Isolate...');
  // Isolateからのメッセージを待つ (Streamとして扱える)
  final result = await receivePort.first;

  print('[Main] Received result: $result');

  print('[Main] Closing ReceivePort and killing Isolate...');
  receivePort.close(); // ポートを閉じる
  isolate.kill(); // Isolateを終了
  print('[Main] Isolate finished.');
}

void main() {
  print('[Main] App started.');
  runComputationInIsolate();
  // Isolateが動いている間もメインスレッドは他の処理を行える
  print('[Main] Doing other work while Isolate runs...');
}

より簡単にIsolateを利用するために、Isolate.run() (Dart 2.19以降) や compute 関数 (flutter/foundation.dart, Flutterプロジェクトの場合) が用意されています。

// Isolate.run() の例 (Dart 2.19+)
import 'dart:isolate';

int performHeavyTask(int value) {
  print('[Isolate.run] Starting task with $value...');
  int result = 0;
  for (int i = 0; i < value * 100000000; i++) {
    result++;
  }
  print('[Isolate.run] Task finished.');
  return result;
}

void main() async {
  print('[Main] Calling Isolate.run...');
  // Isolate.run は Future<R> を返す
  final result = await Isolate.run(() => performHeavyTask(5));
  print('[Main] Result from Isolate.run: $result');
  print('[Main] Finished.');
}

7. エラーハンドリング 🐛

プログラム実行中に発生する可能性のある例外やエラーに対処するための仕組み。

構文/キーワード説明コード例
try例外が発生する可能性のあるコードブロックを囲む。
try {
  // 例外が発生するかもしれない処理
  var result = 100 ~/ 0; // IntegerDivisionByZeroException
  print('Result: $result'); // ここは実行されない
} catch (e) {
  // 任意の例外をキャッチ
  print('An exception occurred: $e');
} finally {
  // 例外の有無に関わらず必ず実行される処理
  print('This block always executes.');
}
catchtryブロック内で発生した例外を捕捉し、処理する。特定の型の例外のみを捕捉することも可能 (onを使用)。例外オブジェクトとスタックトレースを受け取ることもできる。
finallytryブロックの処理が完了した後、例外が発生したかどうかに関わらず、必ず実行されるコードブロック。リソースの解放処理などに使う。
oncatchと組み合わせて、特定の型の例外のみを捕捉する。
try {
  dynamic data = 'not a list';
  print(data.length); // NoSuchMethodError
  // int.parse('abc'); // FormatException
} on FormatException catch (e) {
  print('Caught a FormatException: $e');
} on NoSuchMethodError catch (e, s) { // 例外オブジェクト(e)とスタックトレース(s)
  print('Caught a NoSuchMethodError: $e');
  print('Stack trace:\n$s');
} catch (e) { // 上記以外の全ての例外をキャッチ
  print('Caught some other exception: $e');
}
throw意図的に例外を発生させる。任意のオブジェクトをスローできるが、ExceptionまたはErrorのサブクラスを使うことが推奨される。
void checkAge(int age) {
  if (age < 0) {
    throw ArgumentError('Age cannot be negative.');
  }
  if (age < 18) {
    throw Exception('Must be 18 or older.');
  }
  print('Age is valid.');
}

try {
  checkAge(-5);
} catch (e) {
  print('Error checking age: $e'); // Error checking age: ArgumentError: Age cannot be negative.
}
rethrowcatchブロック内で使用し、捕捉した例外を再度スローする。例外を部分的に処理し、呼び出し元にも通知したい場合などに使う。
void processData() {
  try {
    // ... 何らかの処理 ...
    throw Exception('Internal processing error');
  } catch (e) {
    print('Logging error: $e'); // エラーをログ記録
    rethrow; // 例外を呼び出し元に再スロー
  }
}

void main() {
  try {
    processData();
  } catch (e) {
    print('Main caught error: $e'); // 再スローされた例外をキャッチ
  }
}
  • Exception: 予期される可能性のあるエラー状態を示す。プログラムで捕捉し、回復処理を行うことが想定される(例: IOException, FormatException)。
  • Error: プログラムのバグなど、通常は回復できない深刻な問題を示す(例: ArgumentError, NoSuchMethodError, OutOfMemoryError)。基本的には捕捉せず、プログラムを修正すべき。

8. ライブラリとパッケージ 📦

コードの再利用と整理、外部機能の利用。

他のファイル(ライブラリ)で定義された機能(クラス、関数、変数など)を利用するために使用する。

形式説明コード例
基本形指定したライブラリの全ての公開メンバーを利用可能にする。
// Dartコアライブラリのインポート
import 'dart:math';

// パッケージのライブラリのインポート (後述)
import 'package:http/http.dart';

// プロジェクト内の別ファイルのインポート (相対パス or package: URI)
import 'src/utils.dart';
import 'package:my_project/src/models.dart';

void main() {
  print(pi); // dart:mathから
  // var response = await get(...); // package:http/http.dartから
  // var util = Utils(); // src/utils.dartから
}
プレフィックス付き (as)インポートしたライブラリのメンバーにアクセスする際にプレフィックス(接頭辞)を付ける。名前の衝突を避けるために使う。
import 'package:http/http.dart' as http;
import 'package:my_lib/utils.dart' as myUtils;
// import 'package:other_lib/utils.dart' as otherUtils; // 別のutils

void main() async {
  // httpプレフィックスを付けてアクセス
  var response = await http.get(Uri.parse('https://example.com'));
  print(response.statusCode);

  myUtils.helperFunction();
  // otherUtils.helperFunction();
}
部分的なインポート (show)ライブラリの中から指定したメンバーだけをインポートする。
// dart:math から pi と sqrt のみインポート
import 'dart:math' show pi, sqrt;

void main() {
  print(pi); // OK
  print(sqrt(4)); // OK
  // print(cos(0)); // エラー: cos はインポートされていない
}
部分的なインポート (hide)ライブラリの中から指定したメンバーを除外して、それ以外をインポートする。名前の衝突を避けるためにも使える。
// my_libの MyClass 以外をインポート
import 'package:my_lib/my_lib.dart' hide MyClass;

// 別のライブラリに同名の MyClass がある場合
// import 'package:other_lib/other_lib.dart';

void main() {
  // other_lib の MyClass を使う
  // var obj = MyClass();
  // my_lib の他の機能は使える
  anotherFunctionFromMyLib();
}
遅延読み込み (deferred as)ライブラリを必要になった時点で初めてロードする。初期ロード時間を短縮したい場合や、特定の機能がまれにしか使われない場合に有用。Webアプリで特に効果的。
// heavy_library.dart を遅延読み込み
import 'heavy_library.dart' deferred as heavy;

Future loadAndUseLibrary() async {
  print('Library not loaded yet.');
  // ライブラリをロード (Futureを返す)
  await heavy.loadLibrary();
  print('Library loaded.');
  // ロード後にライブラリの機能を使用
  heavy.heavyFunction();
}

void main() {
  print('App started.');
  // ボタンクリックなどで loadAndUseLibrary() を呼び出す想定
  // loadAndUseLibrary();
}

Dartのパッケージ(ライブラリの配布単位)を管理するための仕組み。pubspec.yamlファイルとdart pub (または flutter pub) コマンドを使用する。

  • pubspec.yaml: プロジェクトの設定ファイル。プロジェクト名、説明、バージョン、依存パッケージなどを記述する。
  • dependencies: アプリケーションが実行時に必要とするパッケージ。
  • dev_dependencies: 開発中にのみ必要とするパッケージ(テスト、ビルドツールなど)。
  • dart pub get (or flutter pub get): pubspec.yamlに記述された依存関係を解決し、パッケージをダウンロード・取得するコマンド。
  • dart pub add <package_name>: パッケージをdependenciesに追加し、pub getを実行する。
  • dart pub remove <package_name>: パッケージをdependenciesから削除し、pub getを実行する。
  • dart pub upgrade: 依存パッケージをpubspec.yamlの制約内で最新バージョンに更新する。
  • pub.dev: DartとFlutterの公式パッケージリポジトリ。利用可能なパッケージを検索できる。
# pubspec.yaml の例
name: my_awesome_app
description: A sample Dart application.
version: 1.0.0
# repository: https://github.com/user/my_awesome_app

environment:
  sdk: '>=3.0.0 <4.0.0' # 対応するDart SDKのバージョン範囲

dependencies:
  http: ^1.1.0       # httpパッケージ (バージョン1.1.0以上、2.0.0未満)
  intl: ^0.18.1      # intlパッケージ (バージョン0.18.1以上、0.19.0未満)
  path: any          # pathパッケージ (任意のバージョン)

dev_dependencies:
  lints: ^2.0.0      # 静的解析ルール
  test: ^1.21.0      # テストフレームワーク

# flutter: # Flutterプロジェクトの場合
#   sdk: flutter
#   uses-material-design: true
#   assets:
#     - images/a_dot_burr.jpeg

コマンドラインでの操作例:

# http パッケージを依存関係に追加
dart pub add http

# test パッケージを開発時依存関係に追加
dart pub add --dev test

# 依存関係を取得/更新
dart pub get

# 依存関係を最新バージョンに更新
dart pub upgrade

# 不要になったパッケージを削除
dart pub remove path

9. その他 📝

その他の便利な構文や機能。

項目説明コード例
コメントコード内に説明やメモを残すための記述。コンパイラには無視される。
// これは単一行コメントです。

/*
これは
複数行コメントです。
*/

/// これはドキュメントコメントです。
/// クラス、メソッド、変数などの説明に使用され、
/// `dart doc` コマンドでドキュメントを生成できます。
/// [他の要素へのリンク](https://dart.dev) や `コードスニペット` も書けます。
class MyClass {
  /// プロパティの説明。
  int value;

  MyClass(this.value);
}
メタデータ (アノテーション)コードに追加情報を提供するための構文。@記号で始まる。コンパイラやツールが解釈して利用する。@override, @required, @deprecated などが組み込みで用意されている。カスタムアノテーションも定義可能。
class Animal {
  void move() { /* ... */ }

  @deprecated // このメソッドは非推奨であることを示す
  void oldMethod() { /* ... */ }
}

class Dog extends Animal {
  @override // スーパークラスのメソッドをオーバーライドしていることを明示
  void move() {
    print('Dog is running');
  }
}

// カスタムアノテーションの例 (定義)
class Todo {
  final String who;
  final String what;
  const Todo(this.who, this.what); // constコンストラクタが必要
}

// カスタムアノテーションの使用
@Todo('Alice', 'Implement this feature')
void doSomethingLater() {
  // ...
}
Typedef関数型に別名を付ける機能。複雑な関数シグネチャを簡潔に表現したり、コードの可読性を向上させたりするのに役立つ。Dart 2.13以降では、関数型だけでなく、任意の型(クラス、ジェネリック型など)にも別名を付けられるようになった。
// 関数型エイリアス (古いスタイル)
typedef IntOperation = int Function(int a, int b);

int add(int x, int y) => x + y;
int subtract(int x, int y) => x - y;

// 関数型エイリアス (新しいスタイル、推奨)
typedef Filter = bool Function(T item);

// 型エイリアス (Dart 2.13+)
typedef IntList = List;
typedef UserMap = Map;


void main() {
  IntOperation operation1 = add;
  IntOperation operation2 = subtract;
  print(operation1(5, 3)); // 8
  print(operation2(5, 3)); // 2

  Filter isLong = (s) => s.length > 5;
  print(isLong('hello')); // false
  print(isLong('dartlang')); // true

  IntList numbers = [1, 2, 3];
  UserMap user = {'name': 'Bob', 'age': 40};
  print(numbers);
  print(user);
}

コメント

タイトルとURLをコピーしました