【Flutter】Dart文法メモ

■Null安全

以下の記法でNull許容の型にできる

```dart
String? title;
List<int>? items;

print(title?.length ?? -1);
```


??= はnullなら代入

```
  static late final HistoryUseCases? _instance;
  HistoryUseCases._();

  factory HistoryUseCases() {
    _instance ??= HistoryUseCases._();
    return _instance!;
  }
  
```
■String
''と""どちらでもいい。一貫性のためにどちらかに統一すること。

■Future型
非同期処理を行うための型
https://zenn.dev/iwaku/articles/2020-12-29-iwaku

■Record型
SwiftのTuppleのように使える

```dart

// 型推測
final record = ('John', 23);
// John
print(record.$1);
// 23
print(record.$2);

// Positional argument
(int name, String age) record2 = ('John', 23);
// John
print(record1.$1);
// 23
print(record2.$2);

// 名前付き引数の利用
(int name, {String age}) record3 = ('John', 23);
// John
print(record1.$1);
// 23
print(record2.age);
```

■mixin型
同じ実装を持つ複数のクラスを管理する仕組み

```dart
mixin Runner {
	void run() {
		print("走ってます");
	}
}

// OK
class Dog with Runner {}
// OK
class Human with Runner {}
```

利用するクラスを制限することも可能
```dart
// Dogの派生クラスのみ使えるよう定義
mixin Runner on Dog {
	void run() {
		print("走ってます");
	}
}

// OK
class Shibaken extends Dog with Runner {}
// NG
class Tanaka extends Human with Runner {}
```

■コレクション

＜List＞
順序付き、重複あり

```dart
// コンストラクタ表記
List<int> myList = [1,2,3];
// リテラル表記（推奨）
final myList2 = <int>[1,2,3];
```

＜Map＞
キーバリュー形式

```dart
// コンストラクタ表記
Map<String, int> myMap = {'key1': 1, 'key2': 2};
// リテラル表記（推奨）
final myMap2 = <String, int>{'key1': 1, 'key2': 2};
// 取得例
int? value = myMap['key2'];
```

＜Set＞
順序なし、重複なし

```dart
// コンストラクタ表記
Set<int> mySet = {1,2,3};
// リテラル表記（推奨）
final mySet2 = <int>{2,3,4};

// 積集合（共通する値を抽出）
Set<int> sekiShugou = mySet.intersection(mySet2);
//3,4となる

// 和集合（2つの集合を合算）
Set<int> waShugou = mySet.union(mySet2);
```

■Stream型とStreamController
単一の変数やコレクションと違い、無限に続くデータの流れに利用
時間と共に変わるデータを継続的に見る時に使う

```dart
  void streamTest() {
    int counter = 0;
    // stream(= 川)に毎秒ごとにperiod(=桃)を流す
    final stream = Stream<int>.periodic(
      const Duration(seconds: 1),
        (int period) => period,
    );

    // stream(=川)を監視し、period(=桃)が流れてきたらcounter(=おばあさん)に渡す
    stream.listen((period){
      counter += period;
    });
  }

  void streamControllerTest() {
    int counter = 0;
    // controller(桃を投げ入れる人)
    final controller = StreamController<int>();

    // stream(= 川)に任意のタイミングでperiod(=桃)を流す
    controller.sink.add(1);

    // stream(=川)を監視し、period(=桃)が流れてきたらcounter(=おばあさん)に渡す
    controller.stream.listen((period){
      counter += period;
    });
  }
```

■型推論と定数、変数
print(変数.runtimeType)
で型を確認できる。
コレクションにも適用できる。

＜const＞
定数。コンパイル時に値と型が確定
->不変の値(URLとか円周率)

```dart
const name = "山田";
const names = ["山田", "田中"];
```

＜final＞
不変（一度だけ代入可能）な変数
->実行された時の条件で値と型が確定する
```dart
final name = "山田";
final persons = {"1": "山田", "2": "田中"};
```

＜var＞
意図的に型推論したい時に利用
```dart
var name = "山田";
var names = <String>{"山田", "田中"}
```

■演算子
~/は割り算の結果を正数で返す

変数の値を文字列に組み込む場合
```dart
String a = ”test $value”
String a = ”test ${value}”
```

■関数
引数なしの関数は呼び出す時に()を省略できる
以下はどちらもOK

```dart
onPressed: _increment,
onPressed: _increment()
```

引数の省略
```dart
// この場合、number2は省略できる
int add({required int number1, int number2})
```

■ループ分
2つ目の引数の条件を満たす間実行される
```dart
for (int i= 0, i<5, i++) {
	print('test $i');
}
// test0からtest4まで5回表示される
```

()の条件を満たす間実行される
```dart
while (i<5){
	print('test $i');
	i++;
}
```

()の条件を満たす間実行される
```dart
do{
	print('test $i');
	i++;
} while(i<5);
```

■Stwitch文
break必要
```
switch(value) {
	case '値1':
		break;
	case '値2';
		break;
	default:
		breadk;
}
```

■Dartの記法一般
_で始まる変数名はprivateになる
変数、定数、関数、クラスどれでも

Dartでは閉じ括弧の後に,をつける
-> indentや括弧の階層構造を見やすく整形してくれる
```
    ),
   },
 ],
),
```

■ラムダ式

ラムダ式=無名関数
関数名なし (int a, int b) {
	return a + b
}

```dart
// 変数に代入する時に便利
// 普通の関数と同じようにadd(1,2)で呼び出せる
final add = 関数名なし (int a, int b) {
	return a + b
}

// 引数なしならこうなる
setState((){
	_test = ++;
});
```

■アロー構文
単に値を返すだけがだったら => の後に返り値を書くことができる
以下はどちらもadd1(1,2)で呼び出せる

```dart
// 関数
int add1(int number1, int number2) => number1 + number2

// 無名関数
final add1 = (int number1, int number2) => number1 + number2
```

■高階関数
- 関数の引数に関数
or
- 関数の返却値を関数にする

```dart
// 高階関数
int apply(int number, Function caclulate) {
	return calculate(number);
}

// 使用例
apply(3, (number) => number *2));
apply(3, (number) {
	return number *2;
}));

[1,2,3,4,5].map((number) => number * 2);
// 2 4 6 8になる

[1,2,3,4,5].where((number) => number %2 == 1));
// 1 3 5になる

ListView.builder(
	itemBuilder: (context, index) {
		// ListTileを繰り返す処理
	}
),
```


■例外処理
onをつけると、特定のエラーをキャッチできる

```dart
try {
	final myList = <int>[1,2,3];
	int item = myList[5];
} on RangeError catch (error) {
	print(error);
} catch (error) {
	print(error);
} finally {
	print("finish");
}
```