Roadmap.shで学ぶFlutter - Advanced Dart - [Core Libraries①: core]

# 導入
[roadmap.shのFlutter](https://roadmap.sh/flutter)の`Core Libraries`に入ります。

ここからが本番感があります。Dartの応用です。
Advanced Dartの項目は「Core Libraries」「Lists」「Collections」「Lambdas」「Functional Programming」「Isolates」「Async/Await」「Streams」「Futures」となっており、どれも難易度が高そうな感じがあります。

順番に「Core Libraries」から進めていきますが、この中にも複数のdartのcoreのライブラリが含まれているので、1つ1つ解説(お勉強)していきます。

:::note warn
Core Librariesの項目は6つありますが、最後のdart:htmlは以下のページに記載がある通り、公式がdart:htmlではなくwebパッケージを利用することを推奨しているため、学習範囲からは除外しました。
https://dart.dev/libraries/dart-html
:::


https://dart.dev/libraries/dart-core

# dart:core
Dartの標準ライブラリには、ビルトイン型、コレクション、およびその他のコア機能が含まれています。このライブラリは、すべてのDartプログラムに自動的にインポートされます。

### 数値

dart:core ライブラリは num, int, double クラスを定義しており、数値を操作するための基本的なユーティリティが含まれています。

文字列を整数や浮動小数点数に変換するには、それぞれ int と double の parse() メソッドを使用します。

```dart
assert(int.parse('42') == 42);
assert(int.parse('0x42') == 66);
assert(double.parse('0.50') == 0.5);
```
また、num の parse() メソッドを使用して、可能であれば整数、それ以外は浮動小数点数として変換することもできます。

```dart
assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);
// 整数の基数を指定するには、radix パラメータを追加します。
assert(int.parse('42', radix: 16) == 66);
```

## 文字列と正規表現
Dartの文字列は、UTF-16コードユニットの不変シーケンスです。正規表現（RegExp オブジェクト）を使用して、文字列の検索や部分置換を行うことができます。

String クラスには、split(), contains(), startsWith(), endsWith() などのメソッドが定義されています。

## 正規表現(Regular Expressions)
RegExp クラスは、JavaScriptの正規表現と同様の機能を提供します。正規表現を使用すると、文字列の効率的な検索やパターンマッチングが可能です。

```dart
// 1つ以上の数字にマッチする正規表現
var numbers = RegExp(r'\d+');

var allCharacters = 'llamas live fifteen to twenty years';
var someDigits = 'llamas live 15 to 20 years';

// contains() メソッドは正規表現も使用可能
assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// マッチするすべての部分を他の文字列に置換
var exedOut = someDigits.replaceAll(numbers, 'XX');
assert(exedOut == 'llamas live XX to XX years');
```

`RegExp` クラスを直接操作することもできます。また、`Match` クラスを使って正規表現のマッチ結果にアクセスすることができます。

```dart
var numbers = RegExp(r'\d+');
var someDigits = 'llamas live 15 to 20 years';

// 文字列に正規表現のマッチがあるか確認
assert(numbers.hasMatch(someDigits));

// すべてのマッチをループで処理
for (final match in numbers.allMatches(someDigits)) {
  print(match.group(0)); // 15 と 20 が出力される
}
```

## 反復処理(Iterator)
Iterable と Iterator クラスは、値のコレクションに対する順次アクセスをサポートします。これらのコレクションを使用する練習として、Iterable collections tutorial がおすすめそうです。

https://dart.dev/libraries/collections/iterables

### Iterableとは？

`Iterable` は、順次アクセス可能な要素のコレクションです。
Iterator を使用すると、コレクション全体を一度にメモリに読み込む必要がありません。代わりに、必要な時に要素を1つずつ生成できます。これにより、大きなデータセットを処理する際のメモリ使用量が抑えられます。

Dartにおいて、`Iterable` は抽象クラスであり、直接インスタンス化することはできません。しかし、新しい `List` や `Set` を作成することで新しい `Iterable` を作成できます。

`List` と `Set` はどちらも `Iterable` であり、`Iterable` クラスと同じメソッドやプロパティを持っています。

`Map` は、実装によって異なるデータ構造を内部で使用します。例えば、`HashMap` はハッシュテーブルを使用し、要素（値とも呼ばれる）はキーを使用して取得されます。`Map` の要素も、`map` の `entries` や `values` プロパティを使用して `Iterable` オブジェクトとして読み取ることができます。

次の例は、`int` の `List` であり、同時に `int` の `Iterable` でもあります。

```dart
Iterable<int> iterable = [1, 2, 3];
```

`List` と `Iterable` の違いは、`Iterable` ではインデックスで要素を読み取る際に効率的であるとは限らない点です。`Iterable` は `List` とは異なり、`[]` 演算子を持っていません。

例えば、以下のコードは無効です。

```dart
Iterable<int> iterable = [1, 2, 3];
int value = iterable[1]; // これは無効なコードです
```

`[]` で要素を読み取ろうとすると、コンパイラは `Iterable` クラスには []演算子が定義されていないと警告します。この場合、`[index]` を使用することはできません。

代わりに、`elementAt()` メソッドを使用して、`Iterable` の要素を指定された位置まで順番にステップすることで要素を読み取ることができます。

```dart
Iterable<int> iterable = [1, 2, 3];
int value = iterable.elementAt(1); // 1番目の要素を取得
```

### 要素の読み取り

`Iterable` の要素は、`for-in` ループを使用して順次読み取ることができます。
以下は、`for-in` ループを使用して要素を読み取る方法を示します。

```dart
Iterable<int> numbers = [1, 2, 3, 4, 5];

for (final number in numbers) {
  print(number);
}
```

## 例外

Dartのコアライブラリは、一般的な例外とエラーを多く定義しています。例外は予測可能でキャッチ可能な条件として扱われますが、エラーは予期しない、または計画していない条件です。

### いくつかの一般的なエラーの例

- NoSuchMethodError
    - 受信するオブジェクト（nullである可能性もある）がメソッドを実装していない場合にスローされます。
- ArgumentError
    - 予期しない引数がメソッドに渡された場合にスローされることがあります。

アプリケーション固有の例外をスローすることは、エラーが発生したことを示す一般的な方法です。独自の例外を定義するには、`Exception` インターフェースを実装します。

```dart
class FooException implements Exception {
  final String? msg;

  const FooException([this.msg]);

  @override
  String toString() => msg ?? 'FooException';
}
```


## 弱参照とファイナライザ

Dartはガベージコレクション（GC）を行う言語であり、参照されていないDartオブジェクトはGCによって破棄される可能性があります。このデフォルトの動作が、ネイティブリソースを含むシナリオやターゲットオブジェクトが変更できない場合には望ましくないことがあります。

- WeakReference
    - 弱参照のことです。ターゲットオブジェクトへの参照を保持しますが、ガベージコレクタによる収集には影響を与えません。別の選択肢として、`Expando` を使用してオブジェクトにプロパティを追加することができます。

- Finalizer
    - オブジェクトが参照されなくなった後にコールバック関数を実行するために使用できますが、このコールバックが実行されることは保証されていません。

- NativeFinalize
    - `dart:ffi` を使用してネイティブコードとやり取りする際に強力な保証を提供し、オブジェクトが参照されなくなった後に少なくとも一度はコールバックが呼び出されます。また、データベース接続や開いているファイルなどのネイティブリソースを閉じるために使用できます。

オブジェクトがガベージコレクションされて早期にファイナライズされるのを防ぐために、クラスは `Finalizable` インターフェースを実装することができます。ローカル変数が `Finalizable` である場合、そのコードブロックが終了するまでガベージコレクションされません。

# 終わりに

この記事では、Dartの「Core Libraries」を中心に、標準ライブラリの基礎から応用までを解説しました。これを活用することで、より効率的で読みやすいコードを書くことができます。

今後、さらに高度なDartの機能や他の標準ライブラリについても学び、スキルを深めていきたいです。

このシリーズでは引き続き、Dartの他のコア機能やライブラリについても掘り下げていきます。