最近我对 Go 语言很感兴趣,一直在考虑用 Go 来做一些实际项目:以 Go 作为主框架,再通过动态加载的方式执行部分程序。不过目前 Go 语言并不支持 Go 模块的动态链接,因此还需要搭配一种脚本语言来补充能力。经过一番筛选后,我觉得 Lua 很符合这个需求:它的虚拟机体积小、运行效率高,而且可以同时开启多个 Lua 虚拟机并并发执行多个 Lua 脚本。于是我继续寻找 Go 与 Lua 的 binding 方案,最后找到了 golua。可惜这个项目已经很久没有更新,在 Go1 环境下甚至无法直接编译通过,我做了一些修改后才勉强编译成功。但继续测试时又发现,没办法把 Go 函数注册到 Lua 中执行,这就比较麻烦了……

没办法,只好自己动手写一个,希望这个 Go Lua binding 至少能满足以下几个需求:
- 可以将 Go 函数注册到 Lua 中,扩展 Lua 的函数库能力
- 可以同时执行多个 Lua 脚本,满足并发调用场景
- 支持 bool、int、float、string 等基础类型之间的相互转换,其他类型暂时先不考虑
- 支持从 Go 中调用 Lua 中定义的函数
- 其他类型统一转换为 Lua 中的 userdate,只能再传回 Go 中使用
- 支持不定参数传递
package main
import (
"fmt"
"glua"
)
type Int struct {
I int
}
func NewInt() *Int {
return &Int{10}
}
func (i Int) PrintInt(str string) {
fmt.Println(str, i.I)
}
func main() {
L := glua.NewState()
L.Openlibs()
var tlib = glua.Libfuncs{
"gotest", // lib name
map[string]interface{}{
"NewInt": NewInt, // lua function name, go function
"PrintInt": (*Int).PrintInt, // lua function name, go function
"goprintln": fmt.Println,
},
}
if ok, err := L.Register(&tlib); !ok {
fmt.Println(err.Error())
return
}
L.Dostring(`gotest.PrintInt(gotest.NewInt(), "Int is")`)
L.Dofile("test.lua")
L.Call("gotest.goprintln", "Call lua function.", 123456)
} --test.lua
gotest.goprintln(true, 123, "lua", gotest.NewInt()) 在 code.google.com/p/glua 可以查看完整代码。编译时需要使用 luajit,因为 Lua 5.1 默认编译出来的是静态库,而 Go1 当时并不支持链接静态库,所以这里最终选择了 luajit 作为底层实现。
