golua库
go和c混合编译的库,通过cgo调用c接口
简介
golua 是一个 Go 语言的库,用于在 Go 程序中嵌入 Lua 脚本引擎。它基于 Lua 的 C API,并通过 cgo 将其与 Go 进行绑定,允许开发者在 Go 应用中调用 Lua 脚本,或者让 Lua 脚本调用 Go 函数。
优缺点(来自deepseek的评价)
本来先让通义评价的,但纯TM乱说,还是deepseek靠谱点
优点
- 轻量级:Lua 本身是一个轻量级脚本语言,适合嵌入到 Go 应用中。
- 高性能:Lua 的执行速度较快,适合作为扩展脚本语言。
- 灵活性:允许动态加载和执行脚本,适合插件系统或配置逻辑。
- 社区支持:Lua 有丰富的库和文档,便于开发。
缺点
- 依赖 CGO:由于是基于 Lua 的 C API,需要 CGO 支持,可能增加构建复杂性。
- 内存管理:Lua 和 Go 的垃圾回收机制不同,可能导致内存管理问题。
- 性能开销:跨语言调用(Go ↔ Lua)会有一定的性能损失。
实际使用中的一些优缺点
优点
- 适合熟悉clua的人玩,不用再去看一遍lua底层代码了
- 直接链接的c库,lua51、52、53、54、jit都能玩
- 还原lua原始的堆栈操作
缺点
- 直接调用c其实很危险,特别是搞扩展c和go交互时,一不小心就崩
- 没法搞预编译,针对多虚拟机的优化应该只有使用对象池了
使用技巧
- 执行lua文件
1
2state := slf.LoadFile(file)
err := slf.Call(slf.GetTop()-1, lua.LUA_MULTRET) - 将go对象注册进lua,并通过lua元表实现go的继承关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54// 向lua虚拟机注册metatable,并指定父类
func (slf *Lua) RegistMetaTableWithParent(
name string,
funcs map[string]lua.LuaGoFunction,
parent string,
) bool {
created := slf.NewMetaTable(MetaKey + name) // 入 1
if !created { // 校验
slf.Pop(1) // 出 0
return false
}
slf.PushString("__index") // 入 2
slf.CreateTable(0, len(funcs)) // 入 3
for fname, f := range funcs {
slf.PushGoFunction(f) // 入 4
slf.SetField(-2, fname) // 出 3
}
slf.LGetMetaTable(MetaKey + parent) // 入 4
found := slf.IsTable(-1) // 校验
if !found {
slf.Pop(1) // 出 3
} else {
slf.SetMetaTable(-2) // 出 3
}
slf.SetTable(-3) // 出 1
slf.Pop(1) // 出 0
return true
}
// 将go对象指针以userdata的形式入栈,并设置其metatable
func (slf *Lua) PushGoPointerWithMetaTable(ptr interface{}, metatable string) bool {
value := reflect.ValueOf(ptr)
if value.Kind() != reflect.Ptr {
return false
}
ptrVal := unsafe.Pointer(value.Pointer())
rawptr := slf.NewUserdata(unsafe.Sizeof(ptrVal)) // 入 1
*(*unsafe.Pointer)(rawptr) = unsafe.Pointer(ptrVal)
// 查找元表
slf.LGetMetaTable(MetaKey + metatable) // 入 2
found := slf.IsTable(-1) // 校验
if !found {
slf.Pop(1) // 出 1
} else {
slf.SetMetaTable(-2) // 出 1
}
return true
}
// 将go对象指针出栈
func (slf *Lua) ToGoPointer(pos int) unsafe.Pointer {
return *(*unsafe.Pointer)(slf.ToUserdata(pos))
}