KotlinとJavaができる人向けDart速習

# この記事について

この資料は[株式会社Diverse](https://qiita.com/organizations/diverse)の社内で使用しているDartを速習したい人向けの教材（2018/08/09作成）を公開したものです。

[社内でのFlutter採用が本決まりになったため](https://developer.diverse-inc.com/entry/2018/09/07/110941)関係エンジニア向けに作成したものですが、多くの人に役立ててもらえる可能性があるため公開と相成りました。

Diverseは今後もコミュニティに貢献する活動を続けてゆきます。
気になった方は @kikuchy または弊社社員へお気軽にご連絡ください。




# まえがき

Kotlinより断然Javaに近い言語なので、Javaベースで話した方が早い箇所が多そう。

以下の前提の人がFlutter開発で不便しない程度にDartを読み書きできるようになることを目標としています。

* 解説するのはDart2
* Java/KotlinをAndroidアプリ開発で一通り使ったことがある
* JavaScriptやRubyもかじったことがある

# 関数/変数スコープ

Kotlinと同じくトップレベルに関数宣言、変数宣言することができます。
mainの宣言もKotlinと同じくトップレベル。


# 不定型

Javaの `Object` 、Kotlinの `Any` と同じく、「何型であってもよい」型は `dynamic` と表記~~します~~できます。

[Effective Dart](https://www.dartlang.org/guides/language/effective-dart/design#do-annotate-with-object-instead-of-dynamic-to-indicate-any-object-is-allowed)によると、「本当に何型であっても良い」ことを示す際には `Object` を、「型Aと型Bのうちどちらか、のような、期待する型が決まってはいるがDartの型システムで表現できない型表現」を `dynamic` でするべき、らしいです。

```dart
/// [arg]を真偽値型に変換する。[arg]はStringかboolじゃないとダメ。
bool convertToBool(dynamic arg) {
  if (arg is bool) return arg;
  if (arg is String) return arg == 'true';
  throw ArgumentError('Cannot convert $arg to a bool.');
}
```


# 可視性

 `_` から始まるメンバ関数/変数が、Javaで `private` キーワードをつけたメソッド/フィールドに相当します。
クラスも `_` から始める名前にできます。

パッケージプライベートはなく、ライブラリプライベートしか存在しないようです。
また、同じライブラリ内であれば `_` で始まるフィールドもクラス外から触れてしまうので、無法者が現れた場合を考慮するならlinterなどで治安維持するしかないかも… 😢


# 型推論

変数の型とか関数の引数とかあちこち推論してくれるみたい。
Kotlinと同程度は推論してくれるとみて良さそう。

```dart
var hoge = "huga";
[1, 2, 3].forEach((x) => print(x*2));
```

これで `hoge` は `String` 型、 `x` は `int` 型と推論されます。
型を指定する場合は `var` の前とか `final` の後とかに型名を書きます。
（ただし `var` は省略が可能。省略すると、Javaの変数定義と同じ書き方になる）


# 変数のデフォルト値

`null` です。なんてこった。
全ての変数は `null` を代入できるので、nullチェックは自分で行わないといけません。なんてこった。
~~（ただ、今後バージョンアップでのNull安全型の導入が決まっているので、将来的にはその必要が無くなりそうです）~~
Dart 2.7でNNBD (Non null by default)がプレビュー導入されました！ :tada: 

ちなみに `assert()` メソッドはproduction環境だとスルーされるようなので、「ある変数や引数にnullが入っていることを期待しない」系はassertで弾くと良いかと思います。

## NNBD

Dart 2.7でプレビュー導入された機能です。
Dart 2.12でstableになりました。

Kotlinと似たような記法で、型レベルでnull安全かそうでないかを識別できます。

```dart
// これはnon-null
final int a = 1;

// なのでこれはエラー
final int b = null;

// nullableであることを示すには型名に ? をつける
final int? c = null;

// nullableな型をnon-nullな型にキャストするには ! をつける。nullに ! を付けるとKotlin同様ランタイムエラーになる
final int d = c!;
```

また、これに伴ってか `required` キーワードが[名前付き任意パラメータ](#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E4%BB%BB%E6%84%8F%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BFoptional-named-parameter%E3%81%A8%E9%A0%86%E5%BA%8F%E4%BB%98%E3%81%8D%E4%BB%BB%E6%84%8F%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BFoptional-positional-parameter)で使えるようになりました。
`required` をつけると、名前付きであるものの必須なパラメータをとることができます。

```dart
// arg1 はnon-nullなString型
void doSomething({required String arg1}) { ... }

// arg1 を省略しようとするとエラー
doSomething(arg1: "hoge");
```

また、 `late` キーワードを使うと、Kotlinの `lateinit var` と同様に初期化のチェックを遅らせることも、 `lazy` delegateと同じように、初期化をメンバ呼び出し時まで遅延することもできます。

```dart
// 初期値を指定しなければ late init var と同じような挙動に。
late TextEditingController _textEditing controller;
// 初期値を指定すれば by lazy {} と同じような挙動に。
late _animationController = AnimationController(vsync: this);
```

`pubspec.yaml` の `environment.sdk` の下限を `2.12` 以上にすることでNNBDを有効にできます。

```pubspec.yaml
environment:
  sdk: ">=2.12.0 <3.0.0"
```



# 再代入不能変数と定数と不変オブジェクト

Javaの `final` 、Kotlinの `val` と同じような機能が似たような感じで使えます。

```dart
final hoge = "fuga";
```

`var` の代わりに `final` を使うと再代入不能変数になります。

ただし、厳密にJavaの `final` （一度代入したら、その後は再代入不可）と同じわけではなく、初期化できるタイミングが限られています。
クラスフィールドに `final` を使った場合には、後述の[初期化子リスト](#初期化子リスト)で初期化しないといけません。
特殊なときじゃないとセッターにアクセスできないフィールドみたいなイメージ？

定数は `const` で宣言します。これも型推論してくれます。
こちらはKotlinの `const val` と同じく、コンパイル時に値が決まっていないといけません。

```dart
const CONSTANT = "VALUE";
```

`const` はリスト系リテラルや値クラスにも使えます。
`const` 宣言された値はメンバを変更できません。（と言っても変更すると例外が飛ぶだけでコンパイル時エラーにはしてくれない。なんてこった）

```dart
// 変数は再代入可能だが、中のリストは変更不可
var hoge = const [1, 2, 3];
```

# 組み込み型の説明

## 数値型

整数型 `int`, `BigInt` と浮動小数点型 `double` しかないっぽいです。
`int` と `double` は `num` の小クラスのようですが、`num`は `dart:math` パッケージを使うときくらいしか意識することないと思います。
また、 `int` は64ビット、2の補数表現なので、それ以上の範囲の数値を扱う場合は `BigInt`を使うことになるかと思います。

リテラルの数値はコンパイル時に解決されるので、 `const` 初期化子は計算式（定数式）でも良いっぽいです。

```dart
const A = 3;
const B = 9;
const C = A * B;
```

## 文字列

```dart
String var str = "こんなふうに"
                        '改行で続けても'
                        "一つの文字列に結合されます。";
str = "JSよろしく" + "加算演算子でも結合が可能です";
str = "Kotlinと同様に $exprName で変数の内容を文字列中に展開できます";
str = """
ダブルクォートもしくはシングルクォートを３つ続けると
複数行文字列リテラルになります。
改行も反映されます。
""";
```


## 真偽値

Javaのプリミティブ `boolean` と同じような `bool` があります。以上。

ただし `bool` 型変数には `null` を入れられてしまうので、初期化時にJavaと同じ気分でいるとバグを作り込む原因になるので注意。


## リスト

Dartに配列はありません。リストがあるだけです。
APIはJavaのListとほぼ同じっぽいですが、Dartにはリストを作るリテラルがあります。

```dart
// これで List<int> になる
final list = [1, 3, 5, 7, 9];

print(list[1]);    // 3
```

Dart 2.3から、リストの中にリストを展開するスプレッド記法もあります。

```dart
final listA = [1, 2, 3, 4];
final listB = [...listA, 5, 6, 7, 8, 9];

print(listB);    // [1, 2, 3, 4, 5, 6, 7, 8, 9]
```

リストリテラル内に要素を追加させる/させないの条件式を書けるCollection-Ifという機能もあります。
こちらの機能もDart 2.3から。

```dart
final list = [
    if (true) 1,
    if (false) 2,
    3
];

print(list);    // [1, 3]
```

何らかの繰り返しの結果をリストにするCollection-Forという機能もあります。
こちらもDart 2.3から

```dart
final listA = [1, 2, 3, 4];
final listB = [
    for (var a in listA) a * 2,
];

print(listB);    // [2, 4, 6, 8]
```

## マップ

APIはJavaのMapとほぼ同じっぽいですが、Dartにはマップを作るリテラルがあります。


```dart
var map = {
    "ほげ": 1,
    "ふが": 2,   // 最後のkey-valueペアの後のカンマはあってもなくても良い
};

print(map["ほげ"]);   // 1
print(map["もげ"]);   // null
```


# 集合

JavaのSetとほぼ同じようなAPIの集合型を作れるリテラルがあります。

```dart
final s = {1, 2, 1, 2, 1, 2};

print(s);    // {1, 2}
```

リストリテラルで使用できたCollection-If, Collection-Forなどは集合のリテラルでも使用できます。


## 字形（Rune）

文字列リテラル中の `\uXXXX` (XXXXは４桁の16進数)、もしくは `\u{XXXXXX}` (`{}` 中は桁数は問わない16進数)で任意のUTF-32コードポイントを表すことができます。
（と[A Tour of the Dart Language](https://www.dartlang.org/guides/language/language-tour#runes)には書かれている）

```dart
var clapping = '\u{1f44f}';
print(clapping);   // 👏
```


## シンボル

JavaにもKotlinにも無い概念。

プログラム中の演算だか同定だかに使用するもので、RubyのSymbolに近いもののようですが、なんか普段使うことがないので気にしなくて良いらしいです。
API作る人とかはもしかしたら使うことがあるのかも。

`#hogehoge` のように `#` で始めるとシンボルになるっぽいです。


## 関数

### 記法

名前付き関数の記法はJavaと一緒。

```dart
String greet(String name) {
    return  "Hello, $name";
}

/*
戻り値型を省略することで戻り値型を推論してくれるらしいですが、
可読性が悪いので省略しないことを勧める、ってEffective Dartに書いてあるそうです
greet(String name) {
    return  "Hello, $name";
}
*/
```

引数だとかで関数型を求められるような場所にはラムダ式を書けます。
変数にラムダ式で宣言した関数を放り込むことも可能。

```dart
var l = [1,2,3];

l.forEach((i) { print(i); });
// 中身が1行だけなら省略形も可能。
//  l.forEach((i) => print(i));
```

ちなみにファットアロー記法 `() => exp` は `() { return exp; }` のシンタックスシュガーらしいです。ラムダ式以外にも、クラスのメソッドの宣言時にも使用できます。
ちゃんと値も返してくれます。

### 名前付き任意パラメータ（Optional named parameter）と順序付き任意パラメータ（Optional positional parameter）

Javaにはない概念です。
Kotlinのデフォルト値付き引数で良いじゃん、って気持ちになる。

Dartの関数は必須パラメータと任意パラメータの二種類をとることができます。
任意パラメータは、関数呼び出し時に値を渡されなくても大丈夫なパラメータです。
そして任意パラメータには、名前付き任意パラメータと順序付き任意パラメータの二種類があります。めんどくさい。

必須パラメータは任意パラメータより先に書かねばならず、任意パラメータは `{}` （名前付き任意パラメータ）または `[]` （順序付き任意パラメータ）でくくる必要があります。

名前付き任意パラメータは、関数呼び出し時に引数ラベルを書かねばならない（代わりに記述順序は任意になっている）引数です。値を渡さない場合はラベルを書かなくても構いません。
値が渡されなかった仮引数には `null` が入ります。

```dart
void enableFlags({bool bold, bool hidden}) {...}

// boldにはnull、hiddenにはtrueが渡される
enableFlags(hidden: true);
```

ちなみに、名前付き任意パラメータの仮引数に `@required` アノテーションを付けると、その仮引数はラベル付きの必須パラメータになります。
`@required` はmetaパッケージに含まれているため、使う際には `package:meta/meta.dart` をimportする必要があります。
ややこしい。

```dart
// childに値を渡さないとエラーになる
const Scrollbar({Key key, @required Widget child})
```

順序付き任意パラメータは、特定の位置以降の引数を省略可能にします。
こちらも値が渡されなかった仮引数には `null` が入ります。

```dart
String say(String from, String msg,
    [String device, String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}

// 第三引数以降は省略可
assert(say('Bob', 'Howdy') == 'Bob says Howdy');

// 引数ラベルは書く必要がない
// 第四引数だけの省略も可能
assert(say('Bob', 'Howdy', 'smoke signal') ==
    'Bob says Howdy with a smoke signal');
```

### デフォルト値

任意パラメータはデフォルト値を持つことができます。
基本Kotlinと同じですが、「デフォルト値をもたせた引数以後の引数にもデフォルト値設定しないといけない」的な縛りはないです。

```dart
String say(String from, String msg,
    [String device = 'carrier pigeon', String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}

assert(say('Bob', 'Howdy') ==
    'Bob says Howdy with a carrier pigeon');
```

デフォルト値として与える値はコンパイル時定数であれば何でも良いです。なので、 `const [...]` とか `const {...}` とかも設定可能。


# スコープ

JavaやKotlinと同じだと考えておけば良さそう。

# 演算子

Javaにはないものだけ解説。

```dart
// Kotlinと同様に ?. で「nullでなかったらメンバ呼び出し」が可能
List<dynamic> list = null;
list?.add(3);    // addは呼び出されないのでエラーにならない

// Javaの / 相当の除算は ~/
int div = 4 ~/ 2;      // 2
div = 4 / 2;           // / だけだとdoubleを返すので、これはコンパイルエラー

// instanceof 相当の型確認演算子は is
bool isHoge = h is Hoge;
bool isNotHoge = h is! Hoge;   // == !(h is Hoge)

// 実はKotlinのSmart Cast相当の事ができる
if (p is Person) {
    print(p.firstName);
}

// Kotlinの ?: （エルビス演算子）相当は ?? （null合体演算子）
var b = a ?? "hoge";

// 変数がnullだったら代入する ??= 演算子がある
a ??= "hoge";
```

# カスケード記法

[A Tour of the Dart Language](https://www.dartlang.org/guides/language/language-tour)ではなぜか演算子の節にまとめられていたけれども、注記に「厳密にはDartの文法機能だよ」と書かれていた。
（[Conditional expressions](https://www.dartlang.org/guides/language/language-tour#conditional-expressions)の`Note:`のところ）


インスタンスの後に `..` を続けることで、メンバにアクセスした上で、その後も `..` を続けて書くことができます。
これを使えばKotlinのapplyスコープ関数相当の事ができます。

```dart
querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
/*
上記は以下のコードに相当する
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
*/

// ()で結合順序を明示する必要があるものの、ネストも可能
final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();
```

# 制御構文

基本は全部Javaと一緒。for-inとかも一緒。
でもIterable舐めるためだったら普通にforEach使ったほうが良い。

switch-case文だけちょっと違いがある。

* すべてのインスタンスをswitchできる？（比較は `==` でなされる）
    * 少なくともint, String, 列挙型は可能
    *  `==` をoverrideしているクラスは対応しないっぽい
* case節には必ず `break` もしくは `continue` を書かないといけない
    * default節（必ず最後に書く必要あり）はbreak書かなくて良い
* `contine label;` で、`label:` をつけたcase節に飛ぶことができる（Cのswitch-caseでbreak省略すると次のcase節の内容が実行されるのと似たような挙動再現のための機能）

```dart
var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}
```

# 例外処理

Javaと似てる。

```dart
try {
  throw Exception("\ﾚｲｶﾞｲﾀﾞﾖ/");
  // なんと任意のインスタンスを例外として投げることが可能
  // 当然型による例外型による条件分類がでめんどくさくなるのでやめたほうが良いと書かれている
  // ならなぜそんな実装にしたんだ…
  // throw "\ﾚｲｶﾞｲﾀﾞﾖ/";
} on Exception catch(e) {
  // 捕まえる型を指定するには on ~~ catch を使う
  // eはException型
  
  // retrhowでtry-catch-finallyブロックの外に例外を投げ直す事ができる
  rethrow;
} catch (e, s) {
  // 型を指定しないcatchは、何型かわからない例外全部キャッチする
  // catchに仮引数を２つ指定すると、２つ目はStackTraceオブジェクトが入る
} finally {
  // finallyブロックは省略可。
}
```


# クラス

クラス宣言の記法とか、すべてのクラスはObjectの子クラスである、という点とかはJavaそっくり。

なお `this` は通常省略するのがDart流らしいです。
（この辺どうするかはチームのコーディングルールによるでしょう）


細かく違うところをざっくり。

* Javaの `instance.class` 相当は `instance.runtimeType`。`Type` 型のインスタンスが返る
* インスタンス化する際の `new` はDart2から書いても書かなくても良い

## コンストラクタでフィールドに値を代入する

Kotlinのコンストラクタ引数に `val/var` を付けるの下位互換っぽいの。

```dart
class Person {
  final String firstName;
  final String lastName;
  
  // これだけでフィールドに値を代入できる
  // コンストラクタのbody内ではすでに代入された状態で使用できる
  // this省略しちゃうと別の仮引数として扱われちゃうっぽい
  Person(this.firstName, this.lastName) {
    ...
  }
}
```

## 名前付きコンストラクタ

Dartのクラスはデフォルト（名前無し）コンストラクタと名前付きコンストラクタを持つことができます。
名前付きコンストラクタはファクトリメソッドの代わりに便利。
そもそもDartはメソッドオーバーロードができないので、複数コンストラクタを持つクラスを作る方法はこれしかない模様。

```dart
class Person {
  final String firstName;
  final String lastName;
  
  Person(this.firstName, this.lastName);
  
  Person.anonymous() {
    this.firstName = "Anoymous";
    this.lastName = "";
  }
}

var p = Person.anoymous();
```


## コンストラクタ継承

Javaと同じく、Dartのコンストラクタは自動的に継承されないので、親クラスのコンストラクタを使いたい場合は明示的に呼び出す必要があります。
でもって、それ専用の記法があります。

```dart
class Mutant extends Person {
  Mutant(String firstName, String lastName) : super(firstName, lastName);
  
  Mutant.anonymous() : super.anonymous() {
    print("anonymous mutant");
  }
}
```

親クラスがデフォルトコンストラクタ（名前無し、かつ、引数なしのコンストラクタ）を持っていない場合は、子クラスは何かしら親クラスのコンストラクタを継承しないといけない決まりがあります。

ちなみに `super` ではなく `this` で自クラスのコンストラクタにリダイレクトすることもできます。


## 初期化子リスト

親クラスコンストラクタを呼び出す記法を使って、メンバの初期化や引数の条件確認などを、コンストラクタのbodyが実行される前に行うことができます。
~~面白いとは思うけど、正直これに意味はあるのだろうか…~~ `final` なフィールドを初期化するときは初期化子リスト内で初期値を代入する必要があります（コンストラクタのbody内で初期化しようとするとコンパイルエラーになる）。

```dart
class Hoge {
  final String fuga;
  Hoge(String moge)
          : assert(moge != null),
          fuga = moge.toUpperCase() {
    print(fuga);
  }
}

/*
これは fugaなんていうセッターはない　と怒られてコンパイルエラーになる
class Dame {
  final String fuga;
  Hoge(String moge) {
    fuga = moge.toUpperCase();
  }
}
*/
```

## 不変コンストラクタ

フィールドが全部 `final` 宣言されていて、コンストラクタの頭に `const` がついていれば、その不変コンストラクタから初期化したインスタンスはコンパイル時定数になれます。

```dart
class Point {
    final int x;
    final int y;
    
    const Point(this.x, this.y);
}

const p = Point(1, 2);
```


## ファクトリコンストラクタ

`factory` をコンストラクタにつけると、ファクトリコンストラクタになります。
ファクトリコンストラクタはJavaのファクトリメソッドとほぼ同じで、中で明示的にインスタンスを返さねばなりません。
シングルトンパターンをするときに便利。

```dart
class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
```


## メソッド

クラス内に関数書けばいい。
`this` で自インスタンスを指せる以外は何も変わらない。

なお、Javaとは違い、メソッドオーバーロードはできません。
基本的に任意パラメータがあればオーバーロードできなくても困ることはないと思いますが。


## ゲッタ/セッタ

メソッドの特殊系。
Kotlinのカスタムgetter/setterの記法と考え方が似てるっちゃ似てるが、どうやら `field` みたいに値をしまうバッキングフィールドまでは用意してくれないみたい。
なので、バッキングフィールドが欲しかったら自分でprivateなフィールドを宣言しておいてやる必要がある。
なんてこったい。

```dart
class Rect {
  final Point point;
  final Size size;
  
  num get area => size.width * size.height;
  
  
  // バッキングフィールドは自動生成されないので自分で作ってやる必要がある
  Color _color;
  
  Color get color => _color;
  set color(Color newColor) {
    _color = newColor;
    notifyColorChanged();
  }
}
```

## 抽象クラスと抽象メソッド

実装しないと怒られるメソッド宣言を持つクラスを宣言できます。
Javaと一緒。

```dart
abstract class Animal {
    void hello();
}

class Cat extends Animal {
  void hello() {
    print("meow");
  }
}
```


## 暗黙的に作られるインターフェイス

Dartには `interface` キーワードが存在しませんが、クラスを宣言した時点でそのクラスと同じAPIのinterfaceが勝手に作られています。
インターフェイスは実装を持ちません。

Javaと同じく `implements` キーワードで実装可能です。

```dart
// Personクラスの宣言であり、greet()メソッドを持ったPersonインターフェイスの宣言でもある。
class Person {
  // privateなものはインターフェイスには含まれない
  final _name;

  // コンストラクタもインターフェイスには含まれない
  Person(this._name);

  // このメソッドのシグネチャはインターフェイスに含まれる
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// Personインターフェイスを実装する
class Impostor implements Person {
  get _name => '';

  // greetを実装しないと怒られる
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}
```

「すべてのクラスはクラスであると当時にインターフェイスであり、extendsするかimplementsするかで性質が違う」と捉えても良いのかもしれない？

## 継承

Java同様の継承もできます。Javaと同じでDartは単一のクラスの継承のみ可。
キーワードとかも親クラスの呼び出し方も全部いっしょ。

## メソッドオーバーライド

Javaと同様` @override` アノテーションを付けることが可能です。任意です。強制にしてくれればいいのに。

オーバーライドするメソッド引数の型を元のメソッドの型より狭めたい場合は、 `covariant` キーワードを付ければ型を変えつつオーバーライドできます。

```dart
class Animal {
  void chase(Animal x) { ... }
}

class Mouse extends Animal { ... }

class Cat extends Animal {
  void chase(covariant Mouse x) { ... }
}
```


## 演算子オーバーライド

C++やGroovyなどと同様に演算子の上書きが可能です。

上書き可能な演算子については[公式のページ参照](https://www.dartlang.org/guides/language/language-tour#overridable-operators)。

ただし `==` を上書きする場合は `hashCode()` メソッドも一緒に上書きする必要があります。
Javaの `equals` と `hashCode` 同時にいじらないとよくない、というのと似てる（両方上書きしないとHashMapとかに入れたとき挙動がおかしくなるので）。

```dart
class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // Operator == and hashCode not shown. For details, see note below.
  // ···
}
```


## noSuchMethod()

Rubyの `method_missing` みたいなメソッドとして `noSuchMethod` なるメソッドがあります。
宣言されていないメソッドをinvokeした際に呼び出されるメソッドです。
これを許しちゃうとタイプセーフとは言えなくなるのでは…？　と思える曲者ですが、どうやら昔の名残で残っている様子。
noSuchMethodが呼び出されるには以下の条件があって、どれか一つに該当する必要があります。

* レシーバーが `dynamic` 型である
    * こちらのパターンの場合、実行時に警告が出る `
Warning: '（メソッド名）' is used reflectively but not in MirrorsUsed. This will break minified code.`
    * [@MirrorsUsed](http://api.dartlang.org/stable/1.24.3/dart-mirrors/MirrorsUsed-class.html)を使うと、事前に指定したメンバの呼び出しについては警告が出なくなる。
* レシーバーの型のメソッドが実装を持っておらず、かつ `noSuchMethod` がオーバーライドされて `Object#noSuchMethod` と実装が異なっている

```dart
class A {
  @override
  void noSuchMethod(Invocation invocation) => print("method ${invocation.memberName} is missing");
}

class B {
  // なんとabstract classでなくても抽象メソッドは持てる
  void hoge();
  
  @override
  void noSuchMethod(Invocation invocation) => print("method ${invocation.memberName} is missing");
}


void main() {
  dynamic a = A();
  a.hoge();

  // なんとabstract classでなければ抽象メソッドを実装しないままインスタンス化できる。嘘だろおい
  B b = B();
  b.hoge();
}
```


# 列挙型

Javaとほぼ同じ。

列挙子は宣言された順にインデックス（0始まり）が割り振られていて、 `index` で参照できる。

```dart
enum Color { red, green, blue }

assert(Color.green.index == 1);
```

switch-case文でも使用可能。

enumを継承できなかったり（mixinにも使えない）、enumのインスタンスを自前で生成できない（定数のみしか使えない）というのもJavaのenumと同じ。

ただし実装を持つことができないのがJavaのenumと違うところ。



# ミックスイン

継承時、mixinクラスを `with` キーワードでミックスイン（継承せずに実装を取り込む）できます。

継承ではないため、複数のクラスをmixinできます。

```dart
mixin AndroidEngineer {
  void implementAndroidApp() {
    print("got it!");
  }
}

mixin IOSEngineer {
  void implementIOSApp() {
    print("Jobs!!");
  }
}

class Person {
}

class FlutterEngineer extends Person with AndroidEngineer, IOSEngineer {
}

void main() {
  final e = FlutterEngineer();
  e.implementAndroidApp();
  e.implementIOSApp();
}
```

`with` は `extends` キーワードとセットでないと使えないので、特に何かを継承せず機能だけ取り込みたい場合は `extends Object with 〜〜` としておくと良いかも。

ミックスインに継承による拡張を施すことはできません。
が、 `on` でミックスイン先を特定のクラスに制限することができるので、これを利用して既存のミックスインを拡張することが可能です。

```dart
mixin Engineer {
  void say(String s) {
    print("Hello world, $s");
  }
}

mixin AndroidEngineer on Engineer {
  void implementAndroidApp() {
    print("got it!");
  }

  @override
  void say(String s) {
    print("Hello droid, $s");
  }
}

class Person {
}

class FlutterEngineer extends Person with Engineer, AndroidEngineer {

}
```


# クラス変数とクラスメソッド

Javaと全く同じです。フィールド宣言やメソッド宣言に `static` を付けるだけ。

`static` メソットはコンパイル時定数扱いなので、constantコンストラクタの引数に渡すことができます。


# ジェネリクス

Javaと基本的に同じ。若干違うところもある。


## 型変数の型を保持する期間

Javaの型変数の状態はコンパイル時にのみ使われていて、実行時には保持されていません。
Dartでは実行時まで保持されているので、実行時に型変数の型を気にするようなコードも書けます。

```dart
final strList = <String>[
  "hoge", "fuga", "moge"
];
assert(strList is List<String>);
```

## 型変数に制限を加える

Javaと同様に `<T extends S>` で「TはSまたはSの小クラスである型」とすることができます。

が、Javaと同様に `<T extends A & B & C>` のようにアンパサンドでつないで複数の条件を設けることはできないようです。
（文法エラーになる）

## メソッドのジェネリクス

Javaとは文法が違うので注意。

```dart
// 型変数の定義を書く位置がメソッド名と仮引数リストの間になっている
// （Javaではアクセス修飾子の戻り値型の間だった）
T doHoge<T>(T value){ ... }
```

昔はメソッドでしかジェネリクス使えなかったっぽいですが、Dart 2では通常の関数でもジェネリクスできるとのこと。

# ライブラリ

## ライブラリを使う

`import '(ライブラリURI)'` でライブラリを読み込めばOK。

### ライブラリのURI

ライブラリは全部URIで表されるようになってます。

接頭辞はジャンルによって違うので、使い分けに注意。

* Dart標準ライブラリ… `dart:` 以下
* サードパーティ製ライブラリ（パッケージマネージャで導入されたライブラリ）… `package:` 以下
    * Flutterのライブラリもサードパーティにあたる
* ネイティブ実装のライブラリ… `dart-ext:` 以下

相対パス指定でパッケージライブラリ化していないソースも参照できます。

### ライブラリ名に別名を付ける

Kotlinのimportと同じ。

```dart
import "package:mylib/awesome_functions.dart" as awesome;
```

### ライブラリの一部の機能だけ使う/除外する

```dart
// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
```

### ライブラリの遅延ロード

なんと遅延ロードが可能です。
使いどころとしては以下のような時があるようです。

* アプリケーションの起動を早くしたい場合
* A/Bテストなどの用途で、都合によって実装を切り替える場合
* 稀にしか出さないような画面やダイアログなど、普段は使わない機能を読み込まず軽くしておきたい場合

遅延ロードするには `deferred as` で別名を付けておく必要があります。

```dart
import "package:rarely_used/lib.dart" deferred as rare;
```

`loadLibrary()` を呼び出すと読み込みが行われますが、`Future` を返すメソッドなので `await` と使わないときついと思います。

```dart
Future doSomething() async {
  await rare.loadLibrary();
  rare.awesomeFunction();
}
```

注意事項とかもいくつかあります。

* 遅延ロードされるライブラリ内でconst宣言されている定数は、ロードを要求する側では定数として扱えません。
    * コンパイル時にその値が存在してないんだから当然といえば当然。
* 遅延ロードするライブラリで宣言されているクラスは使用できません
    * コンパイル時にそのクラスが無いんだから当然といえば当然。
* `deferred as (namespace)` のnamespaceに勝手に `Future loadLibrary()` メソッドが追加されるので注意
    * 同シグネチャのメソッドを置いておいたりしない限り大丈夫

ただ、どうやら[FlutterのDartではまだ実装できていないらしい](https://github.com/dart-lang/sdk/issues/32298)です。残念。
設計を考えておかないと使い所が難しい印象。

## ライブラリを作る

`pubspec.yaml` を置いたり一定のディレクトリ構造を守る必要があったりとか、いろいろ決まり事があります。

外に公開するライブラリを作る機会はまだなさそうなので、必要になったらドキュメントを読みましょう -> [Create Library Packages](https://www.dartlang.org/guides/libraries/create-library-packages)

`lib/` にアプリケーションコードを配置させてたりするので、FlutterアプリケーションもDart的にはライブラリなんですね。


# 非同期サポート

C#やJavaScriptの async/await と似たような感じで、Dartも構文で非同期処理を手続き的に書けるようになっています。

## Future型とasync/await

JavaScriptのPromiseと似たようなものです。
単一の値やエラーがいつか落ちてくるので、落ちてきたときに非同期に処理を行います。
詳しいAPIは[FutureのAPIドキュメント](http://api.dartlang.org/stable/1.24.3/dart-async/Future-class.html)を見てください。

Futureを返すメソッド内であれば、他のFutureを返すメソッドを手続き的な記法で呼び出して結果を待つことができます。

```dart
Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}
```

`await (expression)`  のexpressionはFutureであるのが普通だけれども、もしFuture以外の型だったら勝手にFutureでラップしたことにしてくれるらしい。

main関数もasyncにできる。その場合もちゃんと戻り値は `Future<void>` にしておかないといけない。

```dart
Future main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}
```

async関数の戻り値は勝手にFutureでラップされる。

`async` キーワードを書くのは引数リストの後。
ラムダ式もasyncにできる。

```dart
Future<String> lookUpVersion() async => '1.0.0';
```

try-catch文の中でもawait可能。Futureがエラーを伝えてきた時点で例外が飛んでcatchに移行されます。


## Stream型とasync/await

RxJavaやってる人ならお馴染みのStreamです。
[listen](http://api.dartlang.org/stable/1.24.3/dart-async/Stream/listen.html)してると複数の値やエラーが落ちてくるので、落ちてきたときに非同期に処理を行います。

listenで見張っていてもよいですが、Streamの値を単純なループと同じような文法で記述する `await for` 文があります。

```dart
Future main() async {
  // ...
  await for (var request in requestServer) {
    handleRequest(request);
  }
  // ...
}
```

通常のfor文と同様に `break` や `return` で抜けると、Streamの購読を停止できます。

`await for` も `async` 関数内で使う必要があります。

`await for` は基本的に **終りがある** Streamで使うべきで、UIイベントのストリームなどのエンドレスストリームでは使うべきではありません。
（ループの外から購読を停止するAPIが無いため）
`listen()` で購読すれば [StreamSubscription](http://api.dartlang.org/stable/1.24.3/dart-async/StreamSubscription-class.html)のインスタンスが手に入るので、 `cancel` を叩くことでエンドレスなストリームであっても購読を停止できます。

# ジェネレーター

`Iterable` と `Stream` の値を生成する関数のことです。
`Iterable` の非同期版が `Stream` だと思えばよろしい。


 `Itrable` のジェネレーターはこう書きます。

```dart
// body前に sync* が必要
Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  // yieldで値を返しつつ関数を中断できる
  while (k < n) yield k++;
}
```

`Stream` はこう。`async*` に変わるだけです。

```dart
Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}
```

中身が再帰関数になっている場合は `yield*` で中断するようにします。
多分、末尾再帰最適化とかいろいろやる都合で人間がコンパイラにおしえておいてやらないといけないのでしょう。

```dart
Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}
```


# 呼び出し可能なクラス

Kotlinの `invoke()` と同じです。
`call()` を実装しているクラスのインスタンスは関数同様に `()` を後置すると `call()` が呼び出されます。

```dart
class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

main() {
  final wf = WannabeFunction();
  final out = wf("Hi","there,","gang");
}
```

call()を実装してると関数型としても扱えるっぽいです。


# Isolate

Dartにはスレッドはありません。
すべてのコードはIsolateという単位で動いています。

各Isolateが独立したメモリヒープを持っていて、（特別なことをしなければ）あるIsolateの挙動が他のIsolateの挙動を変えてしまったりする事はありません。

並列処理をしたいときなどは新しいIsolateを立ち上げて、そこで並行処理をおこなわせたりします。

Isolate間でやりとりする場合はPortを開けてそこにデータを流します。

```dart
import "dart:isolate";
import "dart:async";

void w(sendPort) {
    for(int i = 0; i< 100000; i ++) {
      print("waiting: $i");
    }
    sendPort.send("finished!");
}

main() async {
  final receivePort = ReceivePort();
  final sendPort = receivePort.sendPort;
  await Isolate.spawn(w, sendPort);
  receivePort.listen((msg){
    print("message from another Isolate: $msg");
  });
}
```

相互にやり取りする場合はもうちょっと面倒。

[`Isolate.spawnUri()`](http://api.dartlang.org/stable/1.24.3/dart-isolate/Isolate/spawnUri.html) を使えば `main()` 関数が書かれた別ファイルをIsolateとして立ち上げることも可能で、Flutterアプリもこの方法で立ち上げられてます。


# Typedef

Kotlinのtypealiasを関数型に限定したようなやつ。

`typedef` キーワードで関数型の別名を作ることが可能です。

```dart
typedef GestureTapDownCallback = void Function(TapDownDetails details);
```

なんとジェネリクスにすることも可能。

```dart
typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {
  assert(sort is Compare<int>); // True!
}
```

# メタデータ

DartはJava風のアノテーションでコードにメタデータを付与する事ができます。

言語組み込みのアノテーションは[annotations.dart](https://github.com/dart-lang/sdk/blob/master/sdk/lib/core/annotations.dart)を見るとわかります。よく使うのは `@override` と `@deprecated` なんじゃないですかねえ。

デフォルトコンストラクタがconstコンストラクタであるクラスはアノテーションとして使用可能なようです。
クラスやらメンバやらにつけたアノテーションは、リフレクションを使えば実行時に取得可能です。

```dart
import 'dart:mirrors';

class Todo {
  final String comment;
  const Todo(this.comment);
}

@Todo("いつかつくる")
class Hoge {}

main() {
  final h = Hoge();
  final mirror = reflectClass(Hoge);
  final todoRef = mirror.metadata.first;
  print(todoRef.reflectee.comment);
}
```

# コメント

大体Javaと同じ

## 一行コメント

```dart
final hoge = 0;    // 行末までがコメント
```

## 複数行コメント

```dart
/*
    何行でも
    コメント
    できちゃうよ
*/
```

## ドキュメントコメント

[dartdoc](https://github.com/dart-lang/dartdoc#dartdoc)でHTMLのAPIドキュメント吐いてくれるっぽいです。
多分IDEの補完時とかにドキュメント出してくれるだろうと思うので積極的に書いていって問題ないと思います。

```dart
/// 単一行コメントを
/// 複数つなげても
/// ひとつのドキュメントになります。
class Hoge {}

/**
    Javadoc民はこっちの方が慣れてる気がする
    
    Kotlinと同じく [Hoge] とかするとHogeクラスへ参照を張れる
*/
class Fuga {}
```

# 拡張関数

Dart 2.6から正式に、Kotlinの拡張関数と似た雰囲気の拡張関数が作れるようになりました。

```dart
extension NumExtention<T extends num> on T {
  T pow(int p) => math.pow(this, p) as T;
}

print(2.pow(5));  // 32
```

上記のようにジェネリクスも使えますし、extension名を `_` から初めてprivateにすれば、ライブラリ内に閉じ込めておくことも可能です。

ただライブラリのトップレベルでのみ宣言可能なようなので、Kotlinでは可能だった「特定のクラスを継承している子クラス内でのみ使用可能な拡張関数」というのは作れない模様。

----

わからないことがあったらこれを読んでください。
https://www.dartlang.org/guides/language/language-tour