Dart コマンドラインツール

Flutter で使われる Dart 言語について勉強中です。直接 Dart のコマンドラインツールを使っていろいろ試してみます。`dart` コマンドは [Install | Flutter](https://docs.flutter.dev/get-started/install) に従ってインストールした Flutter に付属している物を使います。

資料: [dart: The Dart command-line tool | Dart](https://dart.dev/tools/dart-tool)

上記資料には、`dart_app` というディレクトリに簡単なアプリを作成してテストと実行を行う例が紹介されています。

```shell
dart create -t console my_app
cd my_app
dart analyze
dart test
dart run bin/my_app.dart
```

## Hello World!

ただ、プロジェクトを作成しないで直接 dart のソースコードを実行する事もできます。

```dart:hello.dart
main() {
  print('Hello, World!');
}
```

```shell
$ dart run hello.dart 
Hello, World!
```

Dart の実行には `main()` 関数の実装が必須です。トップレベルに実行文を書く事はできません。また、標準入力からソースを食わすこともできません。試しに `dart /dev/stdin` してみましたが無駄でした。REPL インタラクティブシェルもありません。気軽に Dart で遊ぶには Web で Dart を実行できる [Try Dart in your browser](https://dart.dev/#try-dart) を使うと良いかもしれません。

`dart run` コマンドに `.dart` ファイルを指定すると、プログラムは Dart VM JIT で実行されます。`dart compile` コマンドを使うと事前にコンパイルする事もできます。

## dart compile

`dart compile (サブコマンド) (ソースコード)` のように実行すると、サブコマンドに応じて様々なコンパイルを行う事ができます。例えば実行形式にするには `dart compile exe` を使います。

```shell
$ dart compile exe hello.dart -o hello
Generated: hello
$ ./hello
Hello, World!
```

## Visual Studio Code によるデバッガ

資料: [Launch Configuration - Dart Code - Dart & Flutter support for Visual Studio Code](https://dartcode.org/docs/launch-configuration/)

上記資料によると、メイン関数を `bin/main.dart` に置くなどのお約束に従うと `.vscode/launch.json` がなくても F5 でデバッグできるらしいです。お約束に従わずにメイン関数を `simple/hello.dart` に置いた場合の見本を書きます。`cwd` `program` などの項目は他の言語と各項目は同じですが、上記資料に詳しい説明があります。

```json:.vscode/launch.json
        {
            "name": "hello",
            "cwd": "simple",
            "program": "hello.dart",
            "request": "launch",
            "type": "dart"
        }
```

これで基本的な操作方法は終わりです。以下に Dart の言語機能でつまずいた点をメモします。

## Dart class のコンストラクタ

よく使われる機能なのに慣れないと難しい Dart のコンストラクタについて調べました。

資料: [Dart Super Parameters](https://dart.dev/language/constructors#super-parameters)

まず、普通のクラスを考えます。

```dart
class Pair {
  String? first;
  String? second;
  Pair(String first, String second) {
    this.first = '1-$first';
    this.second = '2-$second';
  }
}
```

わざとらしいですが、コンストラクタで何かしてる感じを出すためにわざわざメンバ変数に代入する時に文字列を加工しています。次に普通にサブクラスを書き始めます。

```dart
class Triplet extends Pair {
  String? third;

  Triplet.standard(String first, String second, String third)
      : super(first, second) {
    this.third = third;
  }
```

`Triplet.standard` という名前付きコンストラクタを作ってみました。コンストラクタの一番基本的な書き方は、このようにコロンの後ろにスーパークラスのコンストラクタ呼び出しを書いて、その後ブロックで囲って初期化を書きます。

```dart
  Triplet.initializer(String first, String second, String third)
      : this.third = third,
        super(first, second);
```

コンストラクタが単に値を代入するだけの場合、コロンの後ろに代入を書く事もできます。

```dart
  Triplet.formal(super.first, super.second, this.third);
```

さらに、formal parameter という機能を使うと、コンストラクタの引数の部分にメンバ変数を書いて初期化を行う事ができます。これは一見みやすくて良いです。

```dart
  Triplet.formal(super.first, super.second, this.third);
```

ところがややこしい事に、super の変数名(?)はコンストラクタの順番と合ってればなんでも良いのです。例えば以下のように `super.foo` `super.bar` のように変数を変えたり `this` との順序を変えても動きます。

```dart
  Triplet.random(super.foo, this.third, super.bar);
```

これは以下と同じような意味になります。

```dart
  Triplet.random0(String foo, String third, String bar) : super(foo, bar) {
    this.third = third;
  }
```

以上 Dart のコンストラクタのトリッキーな機能でした。こりゃわからん。