よくわかるDart 🎯

# 概要
現在弊社でリリースしている iOS アプリの Android バージョン開発に向けて、
Flutter が候補として挙がったので、 Dart について調べました。
どんな言語なのか、どんな書き方ができるのかなど、
1〜2日で調べた内容を共有します。


# 自己紹介
株式会社ITMONOでCTOをしています。
自分のキャリアとしては、サーバーサイドが一番長めで、
Java → PHP → Ruby, Python, Node.js あたりをふらふらしてきました。
直近1~2年はずっとRubyを書きつつ、
最近はSRE的な仕事が多めで、AWSの構築/保守/運用をしています。

# 想定読者
- これから Dart をやってみようかなと思っている人
- Dart がどういう言語なのかさくっと知りたい人

すでに Dart を書いている人向けではないです悪しからず。

# 本編

## 歴史
- JavaScriptの欠点を補うために2011年Googleが公開
- Chromeブラウザに組み込まれる**はず**だった
- 2015年断念し、Javascriptへコンパイルして使う方へ専念
- 2018年最も学ぶ価値のない言語1位になる
- 2018年12月 Google がモバイルSDK **Flutter** をリリース
- 2019年のランキングでは14位まで下がる

## 言語仕様
- クラスベースのオブジェクト指向言語
- 全てがオブジェクト
- 静的型付けができる
- ただ強制ではなく、動的型付けにすることもできる
- `public`, `private` のキーワードはないが、プレフィックスに `_` をつけることで private になる

## インストール

とりあえず Mac に入れる。

```bash
$ brew tap dart-lang/dart
$ brew install dart
$ dart --version
Dart VM version: 2.7.0 (Fri Dec 6 16:26:51 2019 +0100) on "macos_x64"
```

2.7.0 が入った

## Hello world

```dart:hello.dart
void main() {
  print("Hello world");
}
```

```bash
$ dart hello.dart
Hello world
```

Javaっぽい。
`public static` 書かなくていい分楽。
文末セミコロンなきゃだめなのかー

>Every app must have a top-level main() function, which serves as the entrypoint to the app. The main() function returns void and has an optional List<String> parameter for arguments.
https://dart.dev/guides/language/language-tour#the-main-function

`main()` はエントリーポイントとなる関数で、必ずアプリケーションのトップレベルに置く必要がある。
引数として `List<String>` を取る。このへんも Java と同じ。

```dart:hello.dart
void main(List<String> args) {
  print(args[0]);
}
```

```bash
$ dart hello.dart moi!
moi!
```

## エディタ

手軽にブラウザで試せるやつがある
[DartPad](https://dartpad.dev/)

普段は Visual Studio Code 使うのでこのプラグイン入れる
[Dart-Code](https://github.com/Dart-Code/Dart-Code)

他も有名どころはだいたいある感じ。

<img width="1065" alt=" 2019-12-25 20.33.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83183/fc4a265d-fa47-216f-a431-d395d781fbad.png">

## 文法
[samples](https://dart.dev/samples) と[チートシート](https://dart.dev/codelabs/dart-cheatsheet)のやつざっと見ていく。

### 変数

型を明示しない場合は `var` で宣言する

```dart
var name = 'Voyager I';
var year = 1977;
var antennaDiameter = 3.7;
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
var image = {
  'tags': ['saturn'],
  'url': '//path/to/saturn.jpg'
};
```

型を指定する場合は `String` とかをつける。
`dynamic` は `var` と同じ。

```dart
String name = 'Voyager I';
int year = 1977;
double antennaDiameter = 3.7;
List<String> flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
Map<String, dynamic> image = {
  'tags': ['saturn'],
  'url': '//path/to/saturn.jpg'
};
```

初期値を指定しない場合は `null` になる。

```dart
int lineCount; // null
```

### 定数

`final` か `const` を使う。

```dart
final name = 'Bob';
final String nickname = 'Bobby';
```

2つのキーワードの違いは、一度だけ初期化されるか、コンパイル時かみたいなことらしい。

>If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant. (Const variables are implicitly final.) A final top-level or class variable is initialized the first time it’s used.

詳しくは [Final and const](https://dart.dev/guides/language/language-tour#final-and-const) あたりを。

### コレクション

`List`, `Set`, `Map` あたり。 

```dart
final aListOfStrings = ['one', 'two', 'three'];
final aSetOfStrings = {'one', 'two', 'three'};
final aMapOfStringsToInts = {
  'one': 1,
  'two': 2,
  'three': 3,
};
    
final aListOfInts = <int>[];
final aSetOfInts = <int>{};
final aMapOfIntToDouble = <int, double>{};
```



### 制御構文

特に目新しいところはない。Javaと一緒。
`switch` もある。

```dart
if (year >= 2001) {
  print('21st century');
} else if (year >= 1901) {
  print('20th century');
}

for (var object in flybyObjects) {
  print(object);
}

for (int month = 1; month <= 12; month++) {
  print(month);
}

while (year < 2016) {
  year += 1;
}
```

`if` はワンライナーでも書ける。

```dart
var flg = true;
if (flg) print('Hello');
```

条件式は `bool` の値しか取らない。
ここは JavaScript とかと違うところ。
Dart において `true` は `bool true` のみ。

```dart
// Error
var flg = 1;
if (flg) print('Hello');
```

こういうのはいける

```dart
var name = '';
if (name.isEmpty) print('Hello');
```


### 関数
戻り値の型を指定するのが推奨

```dart
int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

var result = fibonacci(20);
```

アロー `=>` を使ったショートハンドも書ける。
無名関数扱うのに便利。
あと `forEach(print)` みたいに引数として渡せる。

```dart
flybyObjects.where((name) => name.contains('turn')).forEach(print);
```

愚直に書くとこんな感じかな？

```dart
bool containsTurn(String name) {
  return name.contains('turn');
}

flybyObjects.where(containsTurn).forEach((name) {
  print(name);
});
```

### インポート
ライブラリや別ファイルのインポート。
ライブラリのインストールは後述。

```dart
// Importing core libraries
import 'dart:math';
    
// Importing libraries from external packages
import 'package:test/test.dart';
    
// Importing files
import 'path/to/my_other_file.dart';
```

### クラス

`宇宙船` クラスで、`名前` と `打ち上げ日` をプロパティとして持っている。
クラス名でコンストラクタを定義する。

```dart
class Spacecraft {
  String name;
  DateTime launchDate;

  Spacecraft(this.name, this.launchDate);
}
```

上のコンストラクタはシンタックスシュガーで、同名のプロパティに値を割り当ててくれる。
これと同義。

```dart
Spacecraft(name, launchDate) {
  this.name = name;
  this.launchDate = launchDate;
}
```

名前付きのコンストラクタも定義できる。
`: this(name, null)` はデフォルトのコンストラクタを続けて呼び出す `super` 的なやつ。

```dart
// Named constructor that forwards to the default one.
Spacecraft.unlaunched(String name) : this(name, null);
```

`getter` はこんな感じ。もちろん `setter` もある。

```dart
int get launchYear => launchDate?.year;
```

メソッドは特に解説要らないすね。
日付まわり使いやすそう。

```dart
void describe() {
  print('Spacecraft: $name');
  if (launchDate != null) {
    int years = DateTime.now().difference(launchDate).inDays ~/365;
    print('Launched: $launchYear ($years years ago)');
  } else {
    print('Unlaunched');
  }
}
```

インスタンス生成も目新しいところはない。

```dart
var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
voyager.describe();

var voyager3 = Spacecraft.unlaunched('Voyager III');
voyager3.describe();
```

### Nullまわりの便利演算子

#### `?.`
`launchDate` が `null` だったら `null` を返す。
`null` でなければ後続のメソッドを呼ぶ。

```dart
launchDate?.year
```

これと同義です。

```dart
(launchDate != null) ? launchDate.year : null;
```

Ruby の `&.hoge` とか `.try(:hoge)` みたいな感じか。

#### `??=`

左辺の値が `null` だったら右辺の値を代入する。
`null` でなければ何もしないみたいなやつ。
Rubyでいうところの `||=`

```dart
int a; // The initial value of a is null.
a ??= 3;
print(a); // <-- Prints 3.

a ??= 5;
print(a); // <-- Still prints 3.
```

#### `??`

先の例で評価をそのまま返すパターン。
Rubyでいうところの `||`

```dart
print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.
```

### 変数展開

`$変数名` で展開される。
Dart ではシングルクォートが推奨されているが、
シングルでもダブルでも展開される。

```dart
print('Launched: $launchYear ($years years ago)');
```

式を書きたいときは `${}` とする。

```dart
print('2 + 3 = ${2 + 3}');
```


### 継承

`extends` キーワードで単一継承です。

```dart
class Orbiter extends Spacecraft {
  num altitude;
  Orbiter(String name, DateTime launchDate, this.altitude) : super(name, launchDate);
}
```

### ミックスイン
`with` キーワードでクラスにメソッドを生やせるやつ。
Ruby の `extend` 的な。

```dart
class Piloted {
  int astronauts = 1;
  void describeCrew() {
    print('Number of astronauts: $astronauts');
  }
}
    
class PilotedCraft extends Spacecraft with Piloted {
  // ···
}

var piloted = PilotedCraft('Piloted Craft I', DateTime(2001, 10,3));
piloted.describeCrew();
```

これインスタンス変数のスコープとかどうなるのかなー。
どっち優先されるとかいろいろ考えないといけないやつかな:thinking: 

### インターフェース

Dart には `interface` というキーワードはない。
あらゆるクラスは**暗黙的に**インターフェースを定義している。

> Dart has no `interface` keyword. Instead, all classes implicitly define an interface. Therefore, you can implement any class.

```dart
class MockSpaceship implements Spacecraft {
  // ···
}
```

インターフェース使いたいならクラスが持つメンバーとメソッド全部実装しろよってことっぽい。

詳しくは [implicit-interfaces](https://dart.dev/guides/language/language-tour#implicit-interfaces)

### 抽象クラス

これはそのままJavaっぽい。
インスタンス化できないクラス。

```dart
abstract class Describable {
  void describe();
    
  void describeWithEmphasis() {
    print('=========');
    describe();
    print('=========');
  }
}
```

### 非同期
`async`/`await` でやる

```dart
const oneSecond = Duration(seconds: 1);
// ···
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}
```

`Future`/`then` を使った書き方もある

```dart
Future<void> printWithDelay(String message) {
  return Future.delayed(oneSecond).then((_) {
    print(message);
  });
}
```

ストリームはこう扱う。

```dart
Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
  for (var object in objects) {
    await Future.delayed(oneSecond);
    yield '${craft.name} flies by $object';
  }
}
```

### カスケード記法

`..` でオブジェクトに対するメソッド呼び出しをチェーンできる。
オブジェクト（`querySelector`）が返ってくるので、プロパティの `classes` とかにアクセスできてる。

```dart
querySelector('#confirm')
    ..text = 'Confirm'
    ..classes.add('important')
    ..onClick.listen((e) => window.alert('Confirmed!'));
```

チェーンしやすい...！

これと同義です。

```dart
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
```

こういうことですね

```dart
// this returns value
myObject.someMethod()
// this returns reference to object
myObject..someMethod()
```

### Optional positional parameters

`[]`で引数をオプショナルにできる

```dart
int sumUp(int a, int b, int c) {
  return a + b + c;
}
    
int total = sumUp(1, 2, 3);

int sumUpToFive(int a, [int b, int c, int d, int e]) {
  int sum = a;
  if (b != null) sum += b;
  if (c != null) sum += c;
  if (d != null) sum += d;
  if (e != null) sum += e;
  return sum;
}
    
int total = sumUptoFive(1, 2);
int otherTotal = sumUpToFive(1, 2, 3, 4, 5);
```

デフォルト値も設定できる。

```dart
int sumUpToFive(int a, [int b = 2, int c = 3, int d = 4, int e = 5]) {
  ...
}
    
int newTotal = sumUpToFive(1);
print(newTotal); // <-- prints 15
```

### Optional named parameters

キーワード引数の。
`{}` シンタックスこれかよとは思うが。

```dart
void printName(String firstName, String lastName, {String suffix}) {
  print('$firstName $lastName ${suffix ?? ''}');
}
    
printName('Avinash', 'Gupta');
printName('Poshmeister', 'Moneybuckets', suffix: 'IV');
    
void printName(String firstName, String lastName, {String suffix = ''}) {
  print('$firstName $lastName ${suffix}');
}
```

### 例外

Javaと違って全部 `unchecked exception` らしい。
これは必ず `catch` しろよみたいなのがない。

> Dart code can throw and catch exceptions. In contrast to Java, all of Dart’s exceptions are unchecked exceptions. Methods don’t declare which exceptions they might throw, and you aren’t required to catch any exceptions.

`Exception`, `Error` の他に `null` 以外のオブジェクトならなんでも投げてよし。

```dart
throw Exception('Something bad happened.');
throw 'Waaaaaaah!';
```

例外の種類は `on` キーワードで定義する。
`catch` は省略できる。例外オブジェクトを参照したい時につける。

```dart
try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}
```

呼び出し元に伝播させるには `rethrow` キーワードを使う。

`finally` は普通にある。

### Initializer lists

なんかコンストラクタで前処理必要なときに先に変換しておけるみたいなこと？
`final` のフィールドはコンストラクタの中身が実行される前に初期化しないといけない事情があるから。

```dart
Point.fromJson(Map<String, num> json) 
    : x = json['x'], 
      y = json['y'] { 
  print('In Point.fromJson(): ($x, $y)');
}
```

> Sometimes when you implement a constructor, you need to do some setup before the constructor body executes. For example, final fields must have values before the constructor body executes. Do this work in an initializer list, which goes between the constructor’s signature and its body:


開発中はアサーション置く場所として使えるねみたいなことも書いてある。

> The initializer list is also a handy place to put asserts, which run only during development:

```dart
NonNegativePoint(this.x, this.y) 
    : assert(x >= 0), 
      assert(y >= 0) { 
  print('I just made a NonNegativePoint: ($x, $y)');
}
```

### Factory constructors

継承してる親クラスから子クラスを透過的にインスタンス化できると。
`factory` なんてキーワード初めて見たな。

```dart
class Square extends Shape {}
    
class Circle extends Shape {}
    
class Shape {
  Shape();
    
  factory Shape.fromTypeName(String typeName) {
    if (typeName == 'square') return Square();
    if (typeName == 'circle') return Circle();
    
    print('I don\'t recognize $typeName');
    return null;
  }
}
```


### Const constructors

噛みそうな名前（笑）

> If your class produces objects that never change, you can make these objects compile-time constants. To do this, define a `const` constructor and make sure that all instance variables are final.

最初からイミュータブルなインスタンスとして生成する。

```dart
class ImmutablePoint {
  const ImmutablePoint(this.x, this.y);
    
  final int x;
  final int y;
    
  static const ImmutablePoint origin = ImmutablePoint(0, 0);
}
```

## [パッケージ](https://dart.dev/tutorials/libraries/shared-pkgs)
Dart のパッケージ管理ツールは `pub`　
[ここ](https://pub.dev/)でパッケージが公開されてる

よくこのドメイン取れたなw

webやサーバーサイド開発なら `stagehand`
モバイル開発なら Flutter のツールを使ってわちゃわちゃやる感じらしい。

サードパーティのライブラリをインストールするためには、自分のアプリをまずパッケージ化しないといけない。
`npm init` 的なノリですね。

`pubspec.yaml` というファイルが必要になる。

`Stagehand` の入手から。

```
$ pub global activate stagehand
Warning: Pub installs executables into $HOME/.pub-cache/bin, which is not on your path.
You can fix that by adding this to your shell's config file (.bashrc, .bash_profile, etc.):
    
export PATH="$PATH":"$HOME/.pub-cache/bin"
    
Activated stagehand 3.3.5.
```

こんなメッセージが出たので言われた通りパスを通して実行すると、
どんな種類のテンプレートが作れるか表示される。

```
$ stagehand
```

とりあえず生成してみる。

```
$ stagehand console-full
```

ファイルやらディレクトリがわちゃわちゃ作成される。

依存関係を`pubspec.yaml` の `dependencies` に記述する。

```yaml
    dependencies:
      vector_math: ^2.0.7
```

`pubspec.lock` とは `Gemfile` `Gemfile.lock` 的な関係なんだろう。

`pub get` でインストールすると、`import` して使えるようになる。

```dart
import 'package:vector_math/vector_math.dart';
    
void main() {
  var x = Vector3.zero(); // Zero vector
  var y = Vector4.all(4.0); // Vector with 4.0 in all lanes
  print('x: $x');
  print('y: $y');
  x.zyx = y.xzz; // Sets z,y,x the values in x,z,z
  print('x: $x');
  print('y: $y');
}
```

## スタイルガイドとか
軽く見ておく。
https://dart.dev/guides/language/effective-dart

### 命名

3種類の規則を使う

- UpperCamelCase
- loweCamelCase
- lowercase_with_underscores

クラスとか型定義には UpperCamel

```dart
class SliderMenu { ... }
    
class HttpRequest { ... }
 
typedef Predicate<T> = bool Function(T value);
```

ライブラリ、パッケージ、ファイル名などは lowercase_with_underscores
これは case-sensitive じゃないファイルシステムがあるから

```dart
library peg_parser.source_scanner;
    
import 'file_system.dart';
import 'slider_menu.dart';
```

メンバ、変数、パラメーターとかは lowerCamel

```dart
var item;
    
HttpRequest httpRequest;
    
void align(bool clearItems) {
  // ...
}
```

定数は今は lowerCamel。
昔は `SCREAMING_CAPS` だったらしいですね。（大文字+アンダースコア）

```dart
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
    
class Dice {
  static final numberGenerator = Random();
}
```

### フォーマット

`dartfmt` でやる。

```
$ dartfmt -w hoge.dart
```

タブではなくスペース。
2つと4つどっちがデファクトなんだろう:thinking: 

他はこのあたり〜
https://github.com/dart-lang/dart_style/wiki/Formatting-Rules

## Tips

プラクティス的なことはこのへん見れば良いと思います。

https://dart.dev/guides/language/effective-dart/usage

`null` を `false` にしたかったらこう、とか

```dart
optionalThing?.isEnabled ?? false;
```

## コミットしてはいけないファイル

https://dart.dev/guides/libraries/private-files

## テスト
https://dart.dev/guides/testing


# 終わり
ざっとでしたが、Javaに根ざしたオブジェクト指向に、
スクリプト系（JavaScript, Ruby, Ptyhon）のエッセンスが入ってて使いやすそうな印象でした〜

次は Flutter 調べよ。