Glojure:在 Go 上托管的 Clojure 解释器

Glojure 是一个实现 Clojure 的解释器,托管在 Go 编程语言之上。与传统的移植不同,Glojure 是一种“托管”语言,这意味着它保持双向关系,所有 Go 值都可以作为 Glojure 值使用,反之亦然,类似于 Clojure 在 JVM 上与 Java 的关系。

核心能力与执行模型

Glojure 使用树遍历解释器进行执行。虽然它目前仍处于早期开发阶段——作者指出应预期会有 bug、缺失功能以及性能受限——但它已经支持了转换后的核心 Clojure 库的相当子集,并且可用于业余项目。

关键技术规格

  • 宿主要求: 需要 Go 1.19 或更高版本(当前安装使用 go 1.24)。
  • 执行方式: 树遍历解释器。
  • 兼容性: 在 v1 正式发布之前不保证向后兼容。
  • 版本: 当前版本为 v0.3.0。

使用方式与部署选项

Glojure 可以作为独立的命令行工具部署,也可以直接嵌入到 Go 二进制文件中。

独立命令行工具 (glj)

glj 命令提供标准的 Clojure 开发体验,包括:

  • 交互式 REPL: 支持 Vi 和 Emacs 编辑模式、多行编辑、Tab 自动完成以及持久化历史记录。
  • 直接求值: -e 标志允许直接在 shell 中求值表达式。
  • 脚本化: 能够将 .glj 脚本作为独立程序运行。

嵌入到 Go 应用中

Glojure 可以作为 Go 应用中的脚本引擎,用于提供可脚本化的配置或插件系统。这使得开发者能够将 Go 的性能与 Clojure 的表达力相结合。开发者可以通过 glj.Varruntime.ReadEval API 从 Clojure 调用 Go 函数,或从 Go 调用 Clojure 函数。

Go 互操作性

互操作是 Glojure 的核心特性,提供对 Go 库的访问方式,类似于 Clojure 访问 Java 框架的方式。

标准库支持

开箱即用,Glojure 为众多 Go 标准库包提供互操作支持,包括 fmtnet/httpostimesyncregexp。为避免与 Clojure 的命名空间语法(使用 /)冲突,包含斜杠的 Go 包名会被改写,例如 net/http 在 Glojure 中变为 net:http

扩展互操作

若要暴露更多 Go 包,开发者可以使用 gen-import-interop 工具生成包映射。生成的 .go 文件随后被导入到应用中,以将所需的包导出添加到 Glojure 的包映射中。

技术差异与对比

类型映射

Glojure 将 Clojure 类型映射到 Go 类型如下:

Clojure 类型 Glojure 类型 备注
long int64
double float64
float float32
byte byte Go 的 byte 为无符号;JVM 的 byte 为有符号
short int16
int int Go 的 int 取决于平台(32/64 位)
char lang.Char 标记的 rune(32 位) vs JVM 16 位
BigInt *lang.BigInt 包装 *big.Int
BigDecimal *lang.BigDecimal 包装 *big.Float
Ratio *lang.Ratio 包装 *big.Rat

与其他 Go‑Clojure 移植的比较

方面 Glojure Joker let-go
托管 Yes No No
可扩展的 Go 互操作 Yes No No
并发 Yes Yes (with GIL) Yes
Clojure 工具链 No Yes No
执行方式 Tree-walk interpreter Tree-walk interpreter Bytecode Interpreter

Sources