Skip to content

0.导言

龙腾道 edited this page Nov 29, 2021 · 2 revisions

TOML:可能是最好的配置文件格式

  配置文件是一种非常基础的文件格式,但远没有数据文件格式(如 SQLite)、文档文件格式(如 Markdown)、编程语言(如 JavaScript)、甚至二进制文件格式(如 PNG)需求那么复杂。

  只要严谨但不严苛、支持必要的数据类型和嵌套,又易于人类手工直接阅读和编辑就可以了。

  但就是这样一种广泛需要而又简单的应用场景,却反而长期以来一直没有一种足够好的文件格式。


  INI(.ini)文件是一种非常原始的基础形式,但各家有各家的用法,而且它最多只能解决一层嵌套。只适合非常非常简单的配置文件,一旦需要两层嵌套,或需要数组,就力不从心了。

; 最简单的结构

val_1 = val_1;
val_2 = val_2; 这些等号后面的值是字符串(句末分号不是必须的;它后面的都是注释)

; 稍微复杂一点的单层嵌套结构

[obj_1]

x = obj_1.x
y = obj_2.y

[obj_2]

x = obj_2.x
y = obj_2.y

  JSON(.json)是一种非常好的数据存放和传输的格式,但阅读和编辑它实在不方便。即便 JSON5(.json5 - ECMAScript 5.1 JSON)这种扩展格式允许了你像写 JavaScript 对象那样书写裸键名、允许尾逗号,并且可以有注释,写多行字符串依然麻烦。即便它将来加上了多行字符串语法,依然不行,因为它虽然是基于括号嵌套语法的层级关系,在不缩进的情况下,却根本没法阅读。

{
    "val_1": "val_1"
    ,
    "val_2": "val_2"
    ,
    "obj_1": {
        "x": "obj_1.x"
        ,
        "y": "obj_1.y"
    }
    ,
    "obj_2": {
        "x": "obj_2.x"
        ,
        "y": "obj_2.y"
    }
    ,
    "arr": [
        { "x":"arr[0].x", "y":"arr[0].y" }
        ,
        { "x":"arr[1].x", "y":"arr[1].y" }
    ]
}

  YAML(.yaml.yml)干脆将 JSON 中有了不够、没有不行的括号结构去掉了,只保留缩进。但编辑和阅读它总令人非常慌张,生怕数错了层次(实际上,对于阅读,语法关键字并不是越小越好)。而且在不支持统一缩进、反缩进、自动在换行时缩进的编辑环境下,这非常麻烦——这本来对编程语言来说不是什么事,但配置文件最常用的使用场景却恰恰是这样。

  另外,YAML 的语法实在太多了,而且不是循序渐进的,即便你不需要复杂的功能,为了保证自己的简单功能不出错,也要对那些复杂的语法有所了解并加以避免(比如究竟什么键名可以不加引号,什么字符串可以不加引号;你总不能为了避免歧义全都加上引号,那和 JSON 也就差球不多了)。更糟的是,纵使如此复杂,想要精确地配置一段多行字符串,却显得力不从心——除非倒退回单行 JSON 字符串表示法,否则其中的换行是否被保留、缩进是否被忽略、是否自动插入了空格、转义的解释等问题,实在令人心力交瘁。再加上各种实现对各种歧义的解释异常混乱……要说规范一点儿责任也没有,似乎是不可能的。

val_1: abcd # string
val_2: true # boolean
val_3: TRUE # ?
val_4: True # ?
val_5: TrUE # ?
val_6: yes  # ?
val_7: on   # ?
val_8: y    # ?

obj_1:
  x: obj_1.x
  y: obj_1.y
obj_2:
  x: obj_2.x
  y: obj_2.y

arr:
  - x: arr[0].x
    y: arr[0].y
  - x: arr[1].x
    y: arr[1].y

str_1: "a
b"          # ?
str_2: "a
        b"  # ?
str_3: "a
         b" # ?

  终于,TOML(.toml)横空出世。它彻底放弃了括号或缩进的底层原理,而是采取了显式键名链的方式。

  为了方便(同时看起来更清楚——这种读和写的契合非常关键!),你可以指定小节名。妙的是,小节名也是可以链式声明的。

  另外,某些数据可能使用内联数组或表更合适以避免臃肿,这也是支持的。

val_1 = "val_1"
val_2 = "val_2"

obj_1.x = "obj_1.x"
obj_1.y = "obj_1.y"

[obj_2]

x = "obj_2.x"
y = "obj_2.y"

[[arr]]

x = "arr[0].x"
y = "arr[0].y"

[[arr]]

x = "arr[1].x"
y = "arr[1].y"

[str.x]

y.z = "str.x.y.z"

[str.a]

b.c = """
    str
   .a
  .b
 .c
""" # 等价于 "    str\n   .a\n  .b\n .c\n"

[inline]

points = [
    { x=1, y=1, z=0 },
    { x=2, y=4, z=0 },
    { x=3, y=9, z=0 },
]

  现在就开始你的 TOML 之旅吧! ​