Starlark 是一种受 Python 强烈影响的动态脚本语言,可以理解为“去掉 Python 大部分系统能力和复杂特性、保留熟悉语法,并专门用于配置、规则和宿主程序扩展的脚本语言”。
Starlark 最初为 Google 的 Bazel 构建系统(类比为 Make,2015 年开源)设计。它的定位不是开发通用应用,而是让宿主程序通过脚本表达配置、规则和扩展逻辑。Starlark 通常被嵌入宿主应用,由宿主程序决定向脚本暴露哪些函数和数据类型。
核心特点
Starlark 的语法基本是 Python 的一个子集,但语言能力明显收敛。它支持动态类型、自动内存管理、词法作用域、一等函数,以及 list、dict、tuple、set 等高级数据类型。
Go 实现目前明确包含 None、bool、bytes、int、float、string、list、tuple、dict、set 和 function 等类型。
与 Python 相比,Starlark 没有 class、异常机制、反射、并发等复杂语言特性,也没有默认的文件、网络、操作系统 API。它强调程序短生命周期、无外部副作用和结果可重复,因此特别适合配置和规则执行。
另一个重要特征是确定性(Determinism):核心语言不会隐式读取当前时间、随机数等外部状态,使相同输入能够得到一致结果,这也是 Bazel 选择它的重要原因。
基本语法
Starlark 对 Python 开发者非常友好:
name = "Starlark"
ports = (80, 443)
config = {
"host": "example.com",
"enabled": True,
}
def add(a, b):
return a + b
for port in ports:
if port == 443:
print("HTTPS:", port)
支持条件、循环、函数、列表、字典、元组、切片、解包等常用语法。例如:
def build(name, replicas=1):
return {
"name": name,
"replicas": replicas,
}
services = [
build("api", 3),
build("worker", 2),
]
因此它的学习成本很低,但不能把普通 Python 程序直接拿过来运行。
使用场景
最典型的应用是 Bazel。Bazel 使用 Starlark 编写 BUILD 文件和 .bzl 扩展规则,用于描述目标、依赖关系、构建规则以及自定义构建逻辑。
除此之外,Starlark 很适合:
- 构建系统和 CI/CD DSL
- 配置文件
- 规则引擎
- 插件系统
- 用户自定义策略
- Go/Java/Rust 应用的脚本扩展
其核心模式是:
宿主程序
↓
注册函数 / 对象 / 类型
↓
Starlark 解释器
↓
执行用户脚本
↓
返回结果
这也是它特别适合 Go 项目的原因。官方 Go 实现 go.starlark.net/starlark 可以直接嵌入 Go 程序。
如果要在 Go 中运行用户提供的简单脚本,同时不允许脚本访问操作系统,Starlark 比直接嵌入 CPython 更符合这种架构。不过“没有系统 API”并不等于完整安全沙箱,生产环境仍应限制脚本执行时间、内存、递归深度和宿主暴露的 API。
版本历史
Starlark 最初叫 Skylark,约在 2015 年随着 Bazel 发展起来,最初实现采用 Java。后来出现 Go 实现,并逐渐将语言规范从 Bazel 的具体实现中独立出来。
2017 年,Go 版本开始发展,形成现在的 starlark-go 项目。
2018 年,由于商标原因,Skylark 正式更名为 Starlark,同时建立独立的语言规范仓库,强调“语言规范”和“具体实现”分离。
目前 Starlark 更适合理解为一套语言规范 + 多种实现,而不是类似 Python 那样严格按照 3.x 演进的单一运行时。Go、Bazel/Java 等实现持续保持兼容和趋同。