Dartでコマンドラインアプリを作ってみる
キッカケ
AtCoderで遊んでいる時にDartを選択し、そもそも標準入力はどうやるんだ?と思いました。
考えてみるとFlutterでDartを触り始めましたが、モバイルアプリを作ること以外で使ったことがなく、Dartについてあまり知らないんじゃないかと思い、Dartのプログラムを組んでみることにしました。
プロジェクトの作り方
前提としてFlutterをインストールしています。
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.22.2, on macOS 13.6 22G120 darwin-arm64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.90.1)
[✓] Connected device (6 available)
[✓] Network resources
• No issues found!
この状態で既にdart
コマンドを実行できるようになっています。
dart言語単体のプロジェクトは以下のコマンドで作成で出来ました。(exampleは任意の名称で)
$ flutter create hallo_world
Hallo World
プロジェクト作成時にFlutterプロジェクト作成時と同様に以下で起動できると言われたのでその通りにまずは実行してみます。
$ cd hallo_world
$ dart run
実行するとコンソールに以下に表示されました。
デフォルトではHello world: 42!
と表示されるプロジェクトが作成されているようです。
$ dart run
Building package executable...
Built hallo_world:hallo_world.
Hello world: 42!
プロジェクトは以下の構成になっていました。
bin/hallo_world.dart
import 'package:hallo_world/hallo_world.dart' as hallo_world;
void main(List<String> arguments) {
print('Hello world: ${hallo_world.calculate()}!');
}
lib/hallo_world.dart
int calculate() {
return 6 * 7;
}
binには実行されるmain関数があり、libはロジックが書かれているので、
基本的にはbinにもろもろ実装し、ロジック実装はlib内に定義、開発している感じだろうと思います。
(testは言わずもがな)
引数
main関数にarguments
があるので、実行時に引数を渡せるのだろうと、引数を表示して実行してみました。
void main(List<String> arguments) {
for (var arg in arguments) {
print(arg);
}
}
$ dart run hallo_world aaaa bbbbb ccccc
Building package executable...
Built hallo_world:hallo_world.
Hello world
aaaa
bbbbb
ccccc
ちなみに引数がある場合はhallo_world
のようにプロジェクト名を指定する必要がありそうでした。
$ dart run aaaa bbbbb ccccc
Could not find package `aaaa` or file `aaaa`
また引数の文字列に意図してスペースを与える場合は''(もしくは"")で囲みます。
$ dart run hallo_world 'a aaa' "bb bbb" "ccc cc"
Building package executable...
Built hallo_world:hallo_world.
a aaa
bb bbb
ccc cc
標準入力
プログラム実行後、入力待ち状態にしてコマンドライン上で入力を待ちそれを表示します。
AtCoderの場合は入力をstdin.readLineSync()
で一行ずつ読み込むようでした。
import 'dart:io';
void main(List<String> arguments) async {
while (true) {
final input = stdin.readLineSync();
if (input == 'exit') {
break;
}
print('output:$input');
}
}
ファイル読み込み
実行時にファイル名を渡して読み込ませ、内容を表示してみます。
import 'dart:io';
void main(List<String> arguments) async {
final path = arguments[0];
final file = File(path);
final lines = await file.readAsLines();
for (var line in lines) {
print(line);
}
}
$ dart run hallo_world input.txt
Building package executable...
Built hallo_world:hallo_world.
111111
222222
333333
引数に指定したinput.txt
はプロジェクトのルートに置いています。
感想
標準入力するプログラムは10年以上昔にC言語やJavaを勉強した時に触ったとき以来で懐かしかったです。
アプリを作る場合は各OSが用意してくれるフレームワーク上にプログラムを書くのが当たり前になっていたので、たまにはcli的なアプリを作るものいいかもと思いました。
Discussion