###### tags: `lang` `ref`
# Dart 文法チートシート
## 変数・定数
```dart
// 変数(・定数)定義
var foo = fun();
final bar = fun(); // 再代入不可
late baz = time_consuming_process(); // baz が参照されるまで、 time_consuming_process() は実行されない
const hoge = 100; // コンパイル時定数
final fuga = const []; // fuga.add(20) のように追加もできない
// 型指定
int? foo = null; // var キーワードがないが、var である
late String bar;
final bar = []; // List<dynamic> になる
final baz = <int>[]; // List<int> になる
final List<int> hoge = []; // List<int> になる
```
## 型
```dart
// 組み込み型
int a = 1;
double b = 2.5;
String c = "test";
bool d = false;
List<int> e = [1, 2, 3, 4];
Set<int> f = {1, 2, 3, 3};
Map<String, int> g = {"a": 1, "b": 2};
int? h = 123; // nullable な変数を定義できる
int i = h!; // ! を使って non-null にキャストできる。もし、h が null だったら例外が飛ぶ
// any 型 (以下の 2 パターンがある)
// - Object?: コンパイル時に型チェックされる
// - dynamic: 実行時に型チェックされる
List<Object?> j = [1, "2", 3.0, null];
List<dynamic> k = [1, "2", 3.0, null];
// キャスト
num l = 256; // num は int と double の super type
double m = l as double; // as キーワードでキャストできる (supertype -> subtype のキャストは OK! subtype -> supertype のキャストは NG!)
int n = l as int;
// typedef
typedef IntList = List<int>;
IntList o = [1, 2, 3];
```
## 制御構文
```dart
// if 文
const num = 500;
if (num % 2 == 0) {
print("even");
} else {
print("odd");
}
// for 文
for (int i = 0; i < 10; i++) {
print(i);
}
for (var c in "test".split("")) {
print(c);
}
// while 文
while (!game.done()) {
game.advance();
}
// switch 文
var command = "RUN";
switch (command) {
case "RUN":
player.run();
case "WAIT":
player.run();
default:
throw 'Unknown command';
}
// try-catch-finally 文
try {
something();
} catch on OutOfMemoryException {
handleOutOfMemoryException();
} catch (e, s) { // catch (e) でも可
print("$s");
rethrow;
} finally {
print("done");
}
```
## 関数
```dart
// エントリポイント
void main() {
print("Hello World\n");
}
// エントリポイント(コマンドライン引数を取るとき)
void main(List<String> args) {
for (final arg in args) {
print(arg);
}
}
// 関数は first-class object
int doubleNum(int n) {
return 2 * n;
}
var l = [1, 2, 3, 4];
print(l.map(doubleNum));
// 匿名関数
print(l.map((n) => 2 * n));
print(l.map((int n) {
return 2 * n;
}));
/*
引数の定義方法
- required positional parameters
- named parameters
- optional positional parameters
*/
void func1(int a, int b, {required int c, int? d, int e = 123}) {}
void func2(int a, int b, [int? c, int d = 123]) {}
func1(1, 2, c: 3);
func1(1, 2, c: 3, d: 4, e: 5);
func2(1, 2, 3);
func2(1, 2, 3, 4);
```
## クラス
```dart
/*
- enum
- abstract classによるインターフェース定義・実装
- mixin
- メソッドのオーバーライド
- 名前付きコンストラクタ
- ジェネリクス
- 継承
*/
import 'dart:math';
enum Gender {
Male,
Female,
Other,
}
// - T はジェネリクスの型パラメータ
// - Dart には interface 構文がない。インターフェースを定義したい場合は abstract class を使う
abstract class Authenticatable<T> {
bool attempt(T credential);
}
mixin PhoneHolder {
String? phoneNumber;
void call() {
if (this.phoneNumber != null) {
print("call ${this.phoneNumber}!");
}
}
}
// - with: mixin 時に使う
// - implements: インターフェースの実装時に使う
// - extends: 継承時に使う
class Person with PhoneHolder implements Authenticatable<String> {
String name;
String pass;
Gender gender;
// コンストラクタ
Person(this.name, this.pass, this.gender);
// 名前付きコンストラクタ
Person.Male(String name, String pass) : this(name, pass, Gender.Male);
Person.Female(String name, String pass) : this(name, pass, Gender.Female);
Person.Other(String name, String pass) : this(name, pass, Gender.Other);
@override
String toString() {
return "name=${this.name} gender=${this.gender}";
}
// Authenticatable<String> インターフェースの実装
bool attempt(String credential) {
return credential == pass;
}
}
class Student extends Person {
static int _nStudents = 0;
String id;
Student(this.id, String name, String pass, Gender gender) : super(name, pass, gender) {
Student._nStudents++;
}
static get nStudents => Student._nStudents;
}
```
```dart
/*
- const コンストラクタ
- 演算子のオーバーロード
*/
class Rectangle {
final int x, y;
// const コンストラクタ
const Rectangle({required this.x, required this.y});
// 演算子のオーバーロード
Rectangle operator *(int scale) => Rectangle(x: scale * this.x, y: scale * this.y);
@override
String toString() => "x=${this.x} y=${this.y}";
}
class Square extends Rectangle {
// コンストラクタ内で例外を投げているので、このコンストラクタは const にできない
Square({required int x, required int y}) : super(x: x, y: y) {
if (x != y) {
throw "is not square. need x=y, but got ${this}";
}
}
}
```
## ジェネレータ
```dart
Iterable<int> range(int n) sync {
var i = 0;
while (i < n) {
yield i;
i += 1;
}
}
```
## 非同期処理
```dart
import 'dart:io';
import 'dart:convert';
Future<String> getURLContent(String url) async {
final client = HttpClient();
final request = await client.getUrl(Uri.parse(url));
final response = await request.close();
final result = await utf8.decodeStream(response);
client.close();
return result;
}
Future<void> main() async {
final result = await getURLContent("https://example.com");
print(result);
}
```