Dart入門中に型について気になったこといろいろ

Dart入門中に型について気になったこといろいろを調べてメモ。

※ 調査は [DartPad (Dart SDK 2.10.2)](https://dartpad.dartlang.org) にて行ったものです。 

### Built-in types
- 組み込み型もすべてオブジェクト。
- コレクションは総称型 (Generics)。

| type | description |
| --- | --- |
| `num` | 数値 |
| `int` | 整数 (numのサブタイプ) |
| `double` | 浮動小数点数 (numのサブタイプ) |
| `bool` | 真偽値 |
| `String` | 文字列 |
| `List<E>` | リスト |
| `Set<E>` | セット（要素の重複不可） |
| `Map<K,V>` | マップ |

あと、Runes とか Symbol とか。

```dart
num numValue = 123;
int intValue = 234;
double doubleValue = 345.678;
bool boolValue = true;
String stringValue = 'Hello, World!';
List listValue = [1, 2, 3];
Map mapValue = {'key1', 1, 'key2': 2};
```

### 型付け
- Dartは静的型付け
- 型推論により型アノテーションがオプショナル
- 特定の型を期待しない場合は `dynamic` を型アノテーションとして付ける


```dart
// 型推論により型アノテーションがオプショナル
int value1 = 123;     // 👉 型アノテーションあり
var value2 = 234.567; // 👉 型アノテーションなしでも型推論により型が決まる

// 特定の型を期待しない場合は dynamic を型アノテーションとして付ける
dynamic value3 = 'Hello, World!';
value3 = 345;

// コレクションの型推論
var list1 = [123, 234, 345];    // 👉 List<int>型
var list2 = [];                 // 👉 List<dynamic>型
var list3 = [123, 23.4, 567];   // 👉 List<num>型
var list4 = [123, 23.4, '567']; // 👉 List<Object>型

var map1 = {'key1': 123, 'key2': 234};   // 👉 Map<String, int>型 
var map2 = {};                           // 👉 Map<dynamic, dynamic>型
var map3 = {'key1': 123, 'key2': 23.4};  // 👉 Map<String, num>型 
var map3 = {'key1': 123, 'key2': '567'}; // 👉 Map<String, Object>型 
```

### 型のキャスト
- キャスト不可能な場合は `TypeError` 例外が発生する。

```dart
dynamic value = 123;

// as によるキャスト
value as int;    // 👉 OK
value as String; // 👉 TypeError: 123: type 'JSInt' is not a subtype of type 'String'

// コレクションの要素のキャスト
List<dynamic> list = [123, 23.4];
list.cast<num>(); // 👉 OK
list.cast<int>(); // 👉 TypeError: 23.4: type 'JSDouble' is not a subtype of type 'int'
```

### nullオブジェクトの操作
- `null`は[Null](https://api.dart.dev/stable/dart-core/Null-class.html)クラスの唯一のオブジェクト
- NullクラスはObjectクラスのサブタイプ
- `null` を特定の型にキャストしても `null` のまま。

```dart
final dynamic value = null;

// 特定の型にキャストしても null のまま
value as int; // 👉 null

// NullクラスもObjectのサブタイプ
value.hashCode;   // 👉 0
value.toString(); // 👉 null

// Nullクラスにない操作は例外が発生する。
value + 1; // 👉 NoSuchMethodError: method not found: '$add' on null
```

### 数値の型変換
- int, double への変換用メソッドで行う
- doubleからintへの変換は常に小数点以下を切り捨て

```dart
123.toDouble();  // 👉 123
123.456.toInt(); // 👉 123
123.999.toInt(); // 👉 123 
```

### 文字列から数値に変換
- int, double に用意された文字列パースメソッドで行う

```dart
int.parse('123');            // 👉 123
int.parse('123.456');        // 👉 FormatException: 123.456
int.parse('1.23e+2');        // 👉 FormatException: 1.23e+2
int.parse('Hello, World!');  // 👉 FormatException: Hello, World!

double.parse('123');           // 👉 123
double.parse('123.456');       // 👉 123.456
double.parse('1.23e+2');       // 👉 123
double.parse('Hello, World!'); // 👉 FormatException: Invalid double\nHello, World!
```


### 数値から文字列に変換
- String への変換用メソッドで行う

```dart
const value = 123.456789;

value.toString();               // 👉 '123.456789'
value.toStringAsExponential(2); // 👉 '1.23e+2'
value.toStringAsFixed(2);       // 👉 '123.46'
value.toStringAsPrecision(2);   // 👉 '1.2e+2'
```

### 文字列補間
- 文字列中に `$object` と記述する
- そのオブジェクトの `toString()` で文字列化したもので補間

```dart
var myName = 'Tom';
var yourAge = 20; 
"I'm $myName. You are $yourAge years old."; // "I'm Tom. You are 20 years old."
```