
TOML(Tom's Obvious, Minimal Language)类似于 JSON 或 YAML,常用于存储配置数据,但语法更简洁,旨在替代语法冗余的 JSON 或功能有限的 INI,成为最小化、易读、无歧义的配置文件格式。
TOML 被广泛应用于各种工具和语言的配置文件中,例如:
- Rust 的包管理器
Cargo使用Cargo.toml。 - Python 的项目管理工具
Poetry使用pyproject.toml。 - Hugo 静态站点生成器使用
config.toml。 - GitHub Actions 的工作流文件也支持使用 TOML 格式。
本教程将详细介绍 TOML 的核心语法、数据类型、高级特性,并通过实例帮助你快速上手。
一、基本语法规则
TOML 的语法设计遵循 "直观、一致、无歧义" 的原则,所有规则都围绕 "让人类易读、机器易解析" 展开,在编写 TOML 文件时,需要遵守以下基本的语法规范。
1. 文件扩展名
TOML 文件使用 .toml 作为扩展名,例如项目配置文件 config.toml、依赖管理文件 pyproject.toml。
2. 注释规则
注释用于添加说明信息,解析器会忽略注释内容,语法为:
- 以
#开头,从#到行尾的所有字符均为注释; - 支持两种注释形式:行注释(
#开头占一行)和行尾注释(#跟在键值对后); - 注意:字符串内部的
#不视为注释标识,会被当作普通字符解析。
示例:
toml
# 这是一个完整的行注释
name = "TOML" # 这是一个行尾注释
another = "# 这不是一个注释"
3. 键值对
键值对是 TOML 文件的基本元素,。每个键值对由一个键和一个值组成,用 = 分隔:
toml
key = "value"
一个完整的键值对(键 + = + 值)必须写在同一行,不能跨越多行拆分。
3.1 键
键(Key)是键值对的标识,用于唯一标识一个值,TOML 提供了多种键的定义方式:
-
裸键(Bare Key) :直接书写,不使用引号包裹,仅允许包含 ASCII 字母(A-Z、a-z)、ASCII 数字(0-9)、下划线(
_)和短横线(-)toml123key = "value" server_port = 80 -
引号键(Quoted Key) :当键名中使用空格、特殊字符(如
@,#,$)或非 ASCII 字符(如中文)时,必须用双引号(")或单引号(')包裹。toml"server address" = "192.168.1.1" 'app-version' = "1.0.0" "中文键名" = "测试内容"
3.2 值
值是配置项的具体内容。TOML 支持多种数据类型,以满足不同的配置需求。
4. 赋值
键值对的键和值之间必须使用 = 分隔:
toml
key = "value"
键在 = 左侧,值在 = 右侧。
5. 大小写敏感
键名、类型标识(如 true/false)均区分大小写,例如 Name 和 name 是两个独立的键,True 不能替代 true;
toml
name
Name
二、基本数据类型
TOML 支持多种数据类型,下面逐一介绍:TOML 的数据类型分为「基础类型」和「复合类型」,覆盖配置场景的所有需求:
1. 字符串 (String)
字符串是最常用的数据类型,TOML 提供了多种写法以适应不同场景。
-
基本字符串 (Basic String) :用双引号
"包裹。支持转义字符,如\n(换行)、\t(制表符)、\"(双引号)、\\(反斜杠) 等。tomltitle = "My \"Awesome\" Project" description = "Line 1\nLine 2" # 会解析为换行 -
多行基本字符串 (Multi-line Basic String) :用三个双引号
"""包裹。可以跨越多行,其中的换行符会被保留。同样支持转义字符。tomllong_text = """ This is a multi-line string. Line 2. "Quotes" are allowed without escaping (except for triple quotes). """ -
字面量字符串 (Literal String) :用单引号
'包裹。不支持任何转义字符 ,所见即所得。不解析任何转义字符(适合写路径、正则表达式等)tomlpath = 'C:\Users\Name\Documents\file.txt' # 这里的 \ 就是普通字符 regex = '^\d{3}-\d{2}-\d{4}$' # 正则表达式中的 \d 不会被转义 -
多行字面量字符串 (Multi-line Literal String) :用三个单引号
'''包裹。同样不支持转义,可以跨越多行,换行符会被保留。tomlcode_block = ''' def hello(): print('Hello, World!') '''
2. 整数 (Integer)
表示整数,支持十进制、十六进制、八进制和二进制。支持整数、浮点数、正负号,以及十六进制 / 八进制 / 二进制(用前缀标识):
toml
# 整数
age = 25
count = -10
# 浮点数
pi = 3.14159
price = 19.99
negative_float = -0.5
# 其他进制(前缀区分)
hex = 0xDEADBEEF # 十六进制(0x 开头)
octal = 0o755 # 八进制(0o 开头)
binary = 0b1010 # 二进制(0b 开头)
3. 浮点数 (Float)
表示小数,也支持科学记数法。
toml
pi = 3.14159
price = 19.99
negative_float = -0.5
scientific_notation = 1e6 # 等于 1000000.0
another_sci_notation = 2.5e-3 # 等于 0.0025
也可以表达特殊的浮点数值。它们总是小写的:
toml
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific
4. 布尔值 (Boolean)
只有 true 和 false(必须小写 ,不能写 True/FALSE):
toml
enabled = true
debug_mode = false
5. 日期时间 (Date and Time)
TOML 内置了对日期、时间和日期时间的支持,精确到秒或毫秒,格式基于 ISO 8601 标准:
-
本地日期 :
YYYY-MM-DDtomlrelease_date = 2025-11-19 -
本地时间 :
HH:MM:SS或HH:MM:SS.sss(带毫秒)tomlstart_time = 09:30:00 precise_time = 14:45:30.123 -
本地日期时间 :
YYYY-MM-DDTHH:MM:SS或YYYY-MM-DDTHH:MM:SS.sss(日期和时间之间用T分隔)tomlevent_datetime = 2023-10-27T15:00:00 -
带时区的日期时间 :
YYYY-MM-DDTHH:MM:SSZ(Z 表示 UTC 时区)或YYYY-MM-DDTHH:MM:SS±HH:MM(时区偏移)tomldeadline_utc = 2023-10-28T00:00:00Z meeting_time = 2023-10-27T10:00:00+08:00 # 东八区
三、复合数据类型
为了表示更复杂的结构,TOML 提供了数组 (Array) 和 表 (Table)。
1. 数组 (Array)
数组用方括号 [] 包裹,元素之间用逗号 , 分隔,支持不同类型的元素(但推荐同类型,更规范):
toml
# 整数数组
numbers = [1, 2, 3, 4]
# 混合类型数组
mixed = [1, "hello", true, 3.14]
# 嵌套数组
matrix = [
[1, 2],
[3, 4]
]
2. 表格 (Table)
表格(Table)用于表示结构化的数据集合,对应 JSON 的「Object」。在头部使用方括号 [table_name] 定义:
toml
[table]
[table_name] 直到下一个表格定义或 EOF 之间都是该表的键值。 表中的键/值对并不保证会按特定顺序排列:
toml
# 定义一个名为 'database' 的表
[database]
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true
上面的 TOML 片段大致等同于以下 JSON:
json
{
"database": {
"server": "192.168.1.1",
"ports": [8001, 8001, 8002],
"connection_max": 5000,
"enabled": true
}
}
嵌套表格 (Nested Tables)
你也可以通过点 . 分隔层级来表示嵌套的结构:
toml
# 嵌套表格(用 . 分隔层级)
[server.ports]
http = 80
https = 443
这等同于:
json
{
"server": {
"ports": {
"http": 80,
"https": 443
}
}
}
你也可以分层次定义,但直接定义更简洁:
toml
[server]
hostname = "example.com"
[server.ports] # 这会在已有的 'server' 表下创建 'ports' 子表
http = 80
https = 443
内联表格 (Inline Table)
对于结构简单的表,可以使用内联表语法,用大括号 {} 包裹,写在一行内:
toml
author = { name = "John Doe", email = "john@example.com" }
这等同于:
toml
[author]
name = "John Doe"
email = "john@example.com"
内联表也可以嵌套:
toml
server = { address = "10.0.0.1", ports = { http = 8080, https = 8443 } }
3. 数组表格(Array of Tables)
当你需要一个表的数组(即 JSON 中的数组对象)时,可以使用双括号 [[]]标注的标题来表示:
toml
[[table_array]]
每个 [[table_array]] 表示数组中的一个元素(对象),对应 JSON 的「对象数组」:
toml
# 定义一个名为 'products' 的数组表
[[products]]
name = "Hammer"
sku = 738594937
[[products]] # empty table within the array
[[products]]
name = "Screwdriver"
price = 9.99 # 数组表中的每个元素可以有不同的键
头部的第一个实例定义了数组及其第一个表元素,并且每个后续实例都会在该数组中创建并定义一个新的表元素,这些表按遇到的顺序插入数组。上面的 TOML 片段大致等同于以下 JSON:
json
{
"products": [
{ "name": "Hammer", "sku": 738594937 },
{ },
{ "name": "Screwdriver", "price": 9.99 }
]
}
数组表也可以嵌套:
toml
[[fruit]]
name = "apple"
[[fruit.varieties]]
name = "red delicious"
[[fruit.varieties]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.varieties]]
name = "cavendish"
这会被解析为一个包含两个 fruit 对象的数组,每个 fruit 对象内部又有一个 varieties 数组,对应 JSON 如下:
json
{
"fruit": [
{
"name": "apple",
"varieties": [
{
"name": "red delicious"
},
{
"name": "granny smith"
}
]
},
{
"name": "banana",
"varieties": [
{
"name": "cavendish"
}
]
}
]
}
四、实践中的 TOML 示例
下面是一个综合性的 pyproject.toml 示例,它展示了 TOML 的多种特性:
toml
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "my-python-project"
version = "0.1.0"
description = "A sample Python project managed with Poetry."
authors = [
"Your Name <your.email@example.com>"
]
license = "MIT"
readme = "README.md"
keywords = ["sample", "demo", "poetry"]
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.26.0"
numpy = "^1.21.0"
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
black = "^21.9b0"
isort = "^5.9.3"
[tool.black]
line-length = 88
target-version = ['py39']
[tool.isort]
profile = "black"
multi