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.Var 和 runtime.ReadEval API 从 Clojure 调用 Go 函数,或从 Go 调用 Clojure 函数。
Go 互操作性
互操作是 Glojure 的核心特性,提供对 Go 库的访问方式,类似于 Clojure 访问 Java 框架的方式。
标准库支持
开箱即用,Glojure 为众多 Go 标准库包提供互操作支持,包括 fmt、net/http、os、time、sync 和 regexp。为避免与 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 |