コーディング · プログラミング言語
Dart入門:初心者向けチュートリアル
結論
DartはGoogleが開発した、静的型付けのオブジェクト指向言語で、アプリフレームワークFlutterの言語として知られています。健全なnull安全を備え、ネイティブコードやJavaScript、WebAssemblyにコンパイルでき、開発中は高速なホットリロードが使えます。このページでは、環境構築、型、null安全、制御構文、関数、コレクション、クラス、非同期処理、エラー処理を順に解説します。
Dartとは何か、何に使われるのか
Dartは、Googleが開発したクライアント向けに最適化されたプログラミング言語です。型推論を備えた静的型付けで、健全なnull安全を持ち、ネイティブの機械語(モバイル、デスクトップ、サーバー向け)にも、JavaScriptやWebAssembly(Web向け)にもコンパイルできます。開発中は仮想マシン上でホットリロードが働くため、実行中のアプリに変更が数秒で反映されます。
多くの人がDartを学ぶ目的は、Flutterでアプリを作ることです。FlutterはGoogleのUIツールキットで、1つのコードベースからAndroid、iOS、Web、Windows、macOS、Linux向けに開発できます。Dartはコマンドラインツールやバックエンドサービスにも使われます。
DartのインストールとHello, worldの実行
dart.devからDart SDKをインストールします(Dartが同梱されたFlutterをインストールしても構いません)。Dartのプログラムは、トップレベルの main 関数から始まります。
// hello.dart
void main() {
print('Hello, world!');
}dart run hello.dart
# Hello, world!
dart compile exe hello.dart # builds a native executable
dart create my_app # creates a new console projectこのページのすべての例は、dartpad.devにあるブラウザ上のエディタ「DartPad」でも試せます。
変数と基本の型
型をコンパイラに推論させるには var、一度だけ代入する変数には final、コンパイル時定数には const を使います。型を明示して書くこともできます。
void main() {
var name = 'Dart'; // inferred as String
int year = 2011; // explicit type
final now = DateTime.now(); // set once, at run time
const pi = 3.14159; // compile-time constant
double ratio = 2; // int literal becomes 2.0
bool ok = year > 2000;
print('$name since $year, pi=${pi.toStringAsFixed(2)}, ok=$ok, ratio=$ratio');
// Dart since 2011, pi=3.14, ok=true, ratio=2.0
print(now.year > 2000); // true
}| 型 | 例 | 補足 |
|---|---|---|
int | 42 | 整数。ネイティブ環境では64ビット |
double | 3.14 | 64ビット浮動小数点数 |
num | 7 または 7.5 | int と double のスーパータイプ |
bool | true | 条件式に使えるのは true と false だけ |
String | 'hi' | UTF-16。$x や ${expr} による文字列補間が使える |
dynamic | 何でも入る | 静的チェックを無効にする。ほとんどのコードでは避ける |
Webでは int の値がJavaScriptの数値として表現されるため、非常に大きな整数では精度が失われることがあります。
健全なnull安全
Dart 3以降、すべてのDartコードで健全なnull安全が使われます。String 型の変数は決してnullにならず、nullを許可するには String? と書きます。コンパイラがすべての使用箇所を検査するので、nullエラーはプログラムを実行する前に検出されます。
int lengthOf(String? s) {
// return s.length; // compile error: s might be null
if (s == null) return 0;
return s.length; // promoted to String after the check
}
void main() {
String? nickname;
print(nickname?.length); // null (null-aware access)
print(nickname ?? 'guest'); // guest (default if null)
nickname ??= 'dee'; // assign only if null
print(lengthOf(nickname)); // 3
late String config; // initialized later, checked at run time
config = 'loaded';
print(config); // loaded
}制御構文
Dartには、おなじみの if、for、while、do-while があり、あらゆるイテラブルを走査する for-in ループも使えます。Dart 3以降は、switch がパターンマッチに対応し、式としても使えます。
void main() {
var scores = [72, 95, 48];
for (var s in scores) {
if (s >= 90) {
print('$s excellent');
} else if (s >= 50) {
print('$s pass');
} else {
print('$s fail');
}
}
for (var i = 0; i < 3; i++) {
print('i = $i');
}
var day = 6;
var kind = switch (day) {
6 || 7 => 'weekend',
>= 1 && <= 5 => 'weekday',
_ => 'invalid',
};
print(kind); // weekend
}関数
関数はファーストクラスのオブジェクトです。引数は位置引数、[] で囲むオプションの位置引数、{} で囲む名前付き引数にできます。名前付き引数は、required を付けない限り省略可能です。アロー構文 => は、1つの式を返す関数の省略記法です。
int add(int a, int b) => a + b;
String greet(String name, {String greeting = 'Hello', required bool loud}) {
var text = '$greeting, $name';
return loud ? text.toUpperCase() : text;
}
String label(String text, [int? width]) =>
width == null ? text : text.padRight(width, '.');
void main() {
print(add(2, 3)); // 5
print(greet('Ana', loud: false)); // Hello, Ana
print(greet('Ana', greeting: 'Hi', loud: true)); // HI, ANA
print(label('id', 5)); // id...
var twice = (int x) => x * 2; // anonymous function
print([1, 2, 3].map(twice).toList()); // [2, 4, 6]
}コレクション:List、Set、Map、レコード
基本のコレクションは、List(順序あり)、Set(重複なし)、Map(キーと値のペア)です。コレクションリテラルでは、if、for、スプレッド演算子 ... が使えます。Dart 3で追加されたレコードは、クラスを宣言せずに複数の値をまとめられます。
void main() {
var nums = [3, 1, 2]; // List<int>
nums.add(4);
nums.sort();
print(nums); // [1, 2, 3, 4]
var tags = {'dart', 'flutter', 'dart'};
print(tags.length); // 2
var ages = {'Ann': 31, 'Bo': 25}; // Map<String, int>
ages['Cy'] = 40;
print(ages['Bo']); // 25
var showAll = false;
var menu = ['Home', if (showAll) 'Admin', for (var n in nums) 'Item $n'];
print(menu); // [Home, Item 1, Item 2, Item 3, Item 4]
(String, int) pair = ('Ann', 31); // a record
var (who, age) = pair; // destructuring
print('$who is $age'); // Ann is 31
}クラスとasync/await
Dartはオブジェクト指向で、すべての値がオブジェクトです。クラスでは、初期化フォーマルパラメータ(this.x)付きのコンストラクタ、名前付きコンストラクタ、ゲッター、ミックスイン、インターフェースが使えます。非同期処理には Future と Stream を async・await とともに使い、ファイルやネットワークの待ち時間でもFlutterアプリの応答性を保てます。
class Point {
final double x, y;
const Point(this.x, this.y);
Point.origin() : x = 0, y = 0; // named constructor
double get sum => x + y; // getter
@override
String toString() => 'Point($x, $y)';
}
Future<String> fetchUser() async {
await Future.delayed(Duration(milliseconds: 100));
return 'ana';
}
Future<void> main() async {
print(Point(1, 2).sum); // 3.0
print(Point.origin()); // Point(0.0, 0.0)
var user = await fetchUser();
print('user: $user'); // user: ana
}エラー処理
例外は throw で投げ、try、on、catch、finally で処理します。特定の型だけを捕捉するには on SomeType を使います。Dartでは、Exception(プログラムが対処できる想定内の問題)と、Error(アサーションの失敗や範囲エラーなどのバグ)を区別しており、Error は通常、捕捉すべきではありません。
int parseAge(String s) {
var n = int.tryParse(s); // null instead of throwing
if (n == null || n < 0) {
throw FormatException('Not a valid age: $s');
}
return n;
}
void main() {
for (var input in ['42', 'abc']) {
try {
print(parseAge(input));
} on FormatException catch (e) {
print('Error: ${e.message}');
} finally {
print('checked $input');
}
}
}
// 42 / checked 42 / Error: Not a valid age: abc / checked abc小さな完成プログラム:ショッピングカートの合計
このプログラムは、クラスで商品を表現し、カートをマップに保持してレシートを表示します。クラス、マップ、文字列の書式設定、コレクションのメソッドを組み合わせています。
class Product {
final String name;
final double price;
const Product(this.name, this.price);
}
void main() {
const apple = Product('Apple', 0.5);
const bread = Product('Bread', 2.25);
final cart = <Product, int>{apple: 6, bread: 2};
var total = 0.0;
cart.forEach((product, qty) {
final line = product.price * qty;
total += line;
print('${product.name.padRight(6)} x$qty ${line.toStringAsFixed(2)}');
});
final count = cart.values.reduce((a, b) => a + b);
print('$count items, total ${total.toStringAsFixed(2)}');
}
// Apple x6 3.00
// Bread x2 4.50
// 8 items, total 7.50次のステップ
- dart.devのDart言語ツアーとチュートリアル。
- 公式のスタイル・設計ガイド「Effective Dart」。
- アプリを作りたい場合は、flutter.devのFlutterドキュメント。
- DartとFlutterのパッケージリポジトリ、pub.dev。
よくある質問
DartはFlutter専用の言語ですか?
いいえ。Dartは汎用言語で、コマンドラインツール、サーバー、Webアプリも作れます。Flutterは、Dartを学ぶ最も人気のある理由というだけです。
Dartはコンパイル言語ですか、インタプリタ言語ですか?
どちらの方式もあります。開発中はVM上でJIT(実行時)コンパイルとホットリロードが働き、リリース時にはAOT(事前)コンパイルでネイティブの機械語に、Web向けにはJavaScriptやWebAssemblyにコンパイルされます。
Dartのfinalとconstの違いは何ですか?
final 変数は一度だけ代入され、その値は実行時に決まっても構いません。const の値はコンパイル時に確定している必要があり、深い不変性を持つため、Flutterは定数ウィジェットを再利用できます。
DartはJavaやJavaScriptに似ていますか?
Cスタイルの構文とクラスは、Java、C#、JavaScriptの開発者には馴染みやすいものです。JavaScriptと違い、Dartは静的型付けで、健全なnull安全を備えています。
Dartの ?? 演算子は何をしますか?
a ?? b は、a がnullでなければ a を、nullなら b を返します。関連する a ??= b は、a がnullの場合にだけ b を a に代入します。