🤔

toml?yaml? 違い調査

に公開

はじめに

最近Rustで何か作りたいという衝動からRustのプロジェクトを作ってみている。
パッケージマネージャーとしてRustはCargoというものを使用している。その依存関係が記載されているファイルはCargo.tomlという。
おや、yamlじゃなくてtoml?

yamlもtomlもなんとなく認知しているだけだったので、違いについて簡単に調べてみる。
(※全部は無理なので一部にします)

結論

  • 記法は違うが、そんなに違わない!
  • アプリで取り入れるなら、ユースケースに応じて選定するべき!(後述)

調査

YAML の書き方

こんな感じで書く。

  • 配列の表現は以下の通りです。
# 基本的な値
title: "My App"
version: 1.0.0
debug: true

# 配列
# 配列の表現方法は2パターンある
ports: [8080, 9000]
features:
  - authentication
  - logging

# ネスト、段落で設定できる。Pythonみたい。
database:
  host: localhost
  port: 5432
  ssl: true

# 複数行文字列 改行するときはパイプを置いて、その後に文字を書けば改行できる
description: |
  これは複数行の
  説明文です

# 参照させることもできる。&や*はGoのポインタのような感じで覚えれば良さげ
default_config: &default
  timeout: 30
  retries: 3

production:
  <<: *default
  host: prod.example.com

TOMLの書き方

こんな感じで書く。

# 基本的な値
title = "My App"
version = 1.0.0
debug = true

# 配列
ports = [8080, 9000]
features = ["authentication", "logging"]

# テーブル
[database]
host = "localhost"
port = 5432
ssl = true

# 複数行文字列
description = """
これは複数行の
説明文です
"""

# 配列テーブル
[[servers]]
name = "alpha"
ip = "10.0.0.1"

[[servers]]
name = "beta"
ip = "10.0.0.2"

YAMLとTOML違いまとめ

以下のような違いがそれぞれである。

項目 YAML TOML
ファイル拡張子 .yaml または .yml .toml
階層表現 インデント(空白/タブ) セクション記法 [section]
文字列 クォートあり/なし両対応 クォートありが基本
複数行文字列 ` または>`
数値型 整数、浮動小数点、8進数、16進数、指数表記 整数、浮動小数点
真偽値 true/false, yes/no, on/off true/false のみ
null値 null, ~, 空文字 対応なし
配列 - item または [item1, item2] [item1, item2] のみ
インライン記法 {key: value} 対応 {key = value} 対応
日付/時刻 ISO8601形式 RFC3339形式(より厳密)
コメント # 行コメントのみ # 行コメントのみ
参照/エイリアス &anchor *alias 対応 対応なし
マルチドキュメント --- で区切り可能 対応なし
文字エスケープ 多数のエスケープシーケンス 基本的なエスケープのみ

YAMLにあってTOMLにない機能

  • 参照とエイリアス: &* を使った値の再利用。
  • マルチドキュメント: 1ファイルに複数の文書を格納
  • null値: nullを明示的に設定することができますが、TOMLはnullがありません
  • 多様な真偽値表現: yes/no, on/off など(いらない気がしますが)
  • 文字列にクォート: クォートなしで表現できる

TOMLにあってYAMLにない機能

  • 厳密な日付時刻型: RFC3339準拠の型安全な日付
  • 配列テーブル: [[table]] による配列状のテーブル定義
# 以下のような構造を[[servers]]とすることで表現できる
# {
#  "servers": [
#    {"name": "web1", "ip": "192.168.1.10", "port": 80},
#    {"name": "web2", "ip": "192.168.1.11", "port": 80},
#    {"name": "db1", "ip": "192.168.1.20", "port": 3306}
#  ]
# }

[[servers]]
name = "web1"
ip = "192.168.1.10"
port = 80

[[servers]]
name = "web2"
ip = "192.168.1.11"
port = 80

[[servers]]
name = "db1"
ip = "192.168.1.20"
port = 3306

まとめ

CargoならTOML、DockerならYAMLなどの既存のエコシステムが採用しているものはそれに従えばいいが、別でアプリで使いたいということならユースケースに応じて使い分けることが必要。

自分的な棲み分けを考えるとすると、

  • 複雑な階層構造を持つ→YAML
  • 同じキーを持つものが多く存在している場合→TOML
    かなと思いました。
    (TOMLの平坦にインデントせずガンガン書けるというのは個人的に好みだなと思いました。)

Discussion