[写経]Rustの練習帳 Chapter 2(その2) 終了コードのお作法
教材
書籍「Rustの練習帳」を使って、教養としての Rust を勉強。
App構造体はどうなった?
clap v4 では App構造体は廃止されたのかを Claude Code くんに質問。
なるほどね。
ということで、書籍のサンプルコードを Command に置き換えて、改めて写経してみる。
use clap::Command;
fn main() {
let _matches = Command::new("echor")
.version("0.1.0")
.author("Ken Youens-Clark <kyclark@gmail.com>")
.about("Rust echo")
.get_matches();
}
実行したところ、書籍と異なり、--helpの出力結果に作者とバージョン情報が含まれなくなってしまった。
$ echor --help
Rust echo
Usage: echor
Options:
-h, --help Print help
-V, --version Print version
バージョンは--version オプションで出力できるが、作者を出力する方法が不明。
設定はできるのに出力できなくなった、なんてことはセキュリティ観点であってもさすがにないよなあ🤔
ということで Command 構造体のリファレンスを確認したところ、 author を表示するには help_template をカスタマイズする必要あり、とのことだった。
注意書きになっているくらいだから、きっとここもv2から仕様が変わったのだろう。
help_template で出力項目を変更したところ、うまくいった🎉
let _matches = Command::new("echor")
.version("0.1.0")
.author("Ken Youens-Clark <kyclark@gmail.com>")
.about("Rust echo")
.help_template("{name} ({version}) - {author}")
.get_matches();
$ echor --help
echor (0.1.0) - Ken Youens-Clark <kyclark@gmail.com>
Arg構造体
書籍のサンプルコードにあった、takes_value や min_values は、v4 の Arg構造体には用意されていない。
Claude Code くんにこのあたりの後継を聞いてみた。
┌─────────────────────────────────────────┬──────────────────────────────────────────────────────┐
│ 旧 (v2/v3) │ 新 (v4) │
├─────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ takes_value(false) (値を取らないフラグ) │ action(ArgAction::SetTrue) (または SetFalse / Count) │
├─────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ takes_value(true) (値を取る) │ action(ArgAction::Set) (または Append) │
└─────────────────────────────────────────┴──────────────────────────────────────────────────────┘
┌─────────────────────────────┬─────────────────┐
│ 旧 │ 新 │
├─────────────────────────────┼─────────────────┤
│ min_values(1) │ num_args(1..) │
├─────────────────────────────┼─────────────────┤
│ max_values(3) │ num_args(..=3) │
├─────────────────────────────┼─────────────────┤
│ min_values(1).max_values(3) │ num_args(1..=3) │
├─────────────────────────────┼─────────────────┤
│ number_of_values(2) │ num_args(2) │
└─────────────────────────────┴─────────────────┘
旧来の min_values のほうがシンプルでわかりやすい気もしたのだけど、範囲指定をしたい時に min_values と max_values の組み合わせが冗長だから num_args に統一したのだろうかね。
v4 向けに修正したコードは以下の通り。
なお、前述の help_template を適用したままだと、出力結果が変わってきてしまうので、外すことにした。
use clap::{Arg, ArgAction, Command};
fn main() {
let matches = Command::new("echor")
.version("0.1.0")
.author("Ken Youens-Clark <kyclark@gmail.com>")
.about("Rust echo")
.arg(
Arg::new("text")
.value_name("TEXT")
.help("Input text")
.required(true)
.num_args(1..),
)
.arg(
Arg::new("omit_newline")
.short('n')
.help("Do not print newline")
.action(ArgAction::SetTrue),
)
.get_matches();
println!("{:#?}", matches);
}
--help の実行結果も、追加オプションに関する出力が増えたので大丈夫。
$ echor --help
Rust echo
Usage: echor [OPTIONS] <TEXT>...
Arguments:
<TEXT>... Input text
Options:
-n Do not print newline
-h, --help Print help
-V, --version Print version
引数無しで実行すると、必須の引数に関する説明が出力されるようになった。
error: the following required arguments were not provided:
<TEXT>...
ここで新たな疑問が。
書籍だと引数無し実行時の終了コード($?)は 1 が返されていたけれど、手元だと 2 が返ってきている。
この微妙な違いは、終了コードの使い分けが賢くなったからだろうか?
ということで、Claude Codeくんを頼る。
┌────────────┬───────────────────────────────────────────────┐
│ 終了コード │ 慣例的な意味 │
├────────────┼───────────────────────────────────────────────┤
│ 0 │ 成功 │
├────────────┼───────────────────────────────────────────────┤
│ 1 │ 一般的なエラー (プログラム実行中の失敗) │
├────────────┼───────────────────────────────────────────────┤
│ 2 │ 使い方の誤り (引数不足・不正なオプションなど) │
└────────────┴───────────────────────────────────────────────┘
ふむ、なるほど😄
引数不足だと 1 ではなくて 2 を返すのが POSIX での慣例、ということすらも知らなかったので、これは良い勉強になった📝
Discussion