Starlark 语言

Starlark 语言 #

Starlark 是一种由 Google 推出的 Python 的方言(曾用名:Skylark),主要用于表达配置,例如 Bazel 的构建文件。也被称为 Bazel 的构建语言,是一个 Python 风格的语言,被广泛用于描述构建和测试的过程。

与 Python 的对比 #

Starlark 和 Python 有很多相似之处,但也有一些不同之处。以下是 Starlark 和 Python 的一些主要异同之处:

相同之处 #

  • 语法:Starlark 的语法非常接近 Python,对于熟悉 Python 的开发者来说,学习 Starlark 会比较容易。
  • 数据类型:Starlark 支持许多 Python 的数据类型,包括数字、字符串、列表、元组、字典等。
  • 控制流:Starlark 支持大部分 Python 的控制流结构,例如 if,for 和 while 等。
  • 参数传递是 call-by-value 方式:对于 immutable 的类型 NoneType, bool, int, float, string 传递的是 alias;对于 mutable 的类型 list, dict, set, tuple 和 function 传递的是 reference。

不同之处 #

  • Starlark 不允许在顶层使用 if 语句和 for 循环,需要在函数内使用。在顶层可以考虑用 list comprehension 代替 for 循环,赋值表达式中的 if 可以被允许。
  • Starlark 默认不支持无限循环(while 语句)和递归,除非使用 -recursion 标志运行解析器。
  • 字典遍历顺序是恒定的,不允许有重复的 key。
  • 循环中不允许改变集合内容。
  • 字符串不允许被循环依次读取元素。
  • Starlark 的全局变量一旦被定义,就不能被修改,这也是为了保证其并发安全性和构建的可预测性。
  • Starlark 没有 import 语句,而是使用 load 语句来加载其他文件的指定内容,加载的模块中的变量都是不可变的,被 freeze 了。
  • 单元素的元组必须有括号,例如 x = (1,),而 Python 中可以写作 x = 1,
  • boolint 之间不能做计算,例如 True < 2True + True 都不被允许。
  • Starlark 没有错误处理机制,没有 tryexceptfinally 语句,提供了 fail 函数来报告错误。
  • Starlark 没有类和对象,没有面向对象的特性。
  • Starlark 和 Python 的内置函数库有所不同,Python 中大部分系统内置的库,比如文件操作,在 Starlark 中是没有的,需要自行在外部实现。
  • Starlark 是线程安全的,这意味着 Starlark 的函数可以在多线程环境中并行执行,而不会有数据竞争的问题,这是受益于 Starlark 的设计中禁止了数据的共享和修改。

运行模式 #

通过阅读 此文档我们可以对 Starlark 的执行模式和特点进行如下总结——

Starlark 作为一种编程语言具有以下执行模式和特点:

  • Starlark 文件定义了一个模块,该模块是全局变量名称到其值的映射。当 Starlark 文件被执行时,无论是直接由应用程序执行还是间接通过 load 语句执行,都会创建一个新的 Starlark 线程。该线程会执行文件中的所有顶层语句。由于 if 语句和 for 循环不能出现在函数外部,因此控制流从上到下进行。
  • 如果执行到达文件的末尾,模块初始化就成功了。此时,模块的每个全局变量的值被冻结,无法再进行更改。模块随后就准备好被其他 Starlark 线程使用,比如执行 load 语句的线程。这些线程可以访问已加载模块中定义的值或调用函数。
  • Starlark 线程可能代表其嵌入的应用程序携带状态,而应用程序定义的函数可能根据此线程状态表现得不同。由于模块初始化总是在新线程中进行,因此线程状态永远不会从高级模块传递到低级模块。因此,模块的初始化行为与触发其初始化的模块无关。
  • 如果 Starlark 线程遇到错误,执行会停止,错误会报告给应用程序,同时会返回一个回溯,显示错误发生时的活动函数调用堆栈。如果在 Starlark 模块的初始化过程中发生错误,等待模块初始化的任何活动 load 语句也会失败。
  • Starlark 不提供错误处理机制。错误发生时,会立即停止执行,并报告给应用程序。

深度理解 Starlark 的执行模式和特点,可以看出它设计上的一些特性:

  • 模块化和封装:每个 Starlark 文件定义了一个模块,模块内的全局变量被冻结,无法被更改。这可以防止模块间的全局状态干扰,并提高代码的复用性和可维护性。
  • 线程安全性:每次执行 Starlark 文件都会创建一个新的线程,线程的状态不会从一个模块传递到另一个模块。这意味着 Starlark 的执行是线程安全的,能在并发环境下正确运行。
  • 错误处理:Starlark 的错误处理机制很简单,任何错误都会导致执行停止,并报告给应用程序。这使得错误处理变得简单直接,但也意味着 Starlark 编程需要特别小心,避免错误的产生。
  • 应用程序与 Starlark 的交互:Starlark 线程可以携带应用程序的状态,这意味着应用程序可以通过 Starlark 线程调整其行为。同时,应用程序也需要处理 Starlark 的错误,因为 Starlark 本身不提供错误处理机制。

总的来说,Starlark 的设计强调了模块化、封装、线程安全性和错误的直接处理,这使得它非常适合用作嵌入应用程序的脚本语言。

参考资料 #

关键词表(避免用于变量名、函数名):

and            elif           in             or
break          else           lambda         pass
continue       for            load           return
def            if             not            while

as              except          nonlocal
assert          finally         raise
async           from            try
await           global          with
class           import          yield
del             is