github.com/yuin/gopher-lua
基本使用
执行字符串
L := lua.NewState()
defer L.Close()
if err := L.DoString(`print("hello")`); err != nil {
panic(err)
}
执行文件
L := lua.NewState()
defer L.Close()
if err := L.DoFile("hello.lua"); err != nil {
panic(err)
}
数据类型
Type name | Go type | Type() value | Constants |
---|---|---|---|
LNilType |
(constants) | LTNil |
LNil |
LBool |
(constants) | LTBool |
LTrue , LFalse |
LNumber |
float64 | LTNumber |
- |
LString |
string | LTString |
- |
LFunction |
struct pointer | LTFunction |
- |
LUserData |
struct pointer | LTUserData |
- |
LState |
struct pointer | LTThread |
- |
LTable |
struct pointer | LTTable |
- |
LChannel |
chan LValue | LTChannel |
- |
数据类型判断LNilType
and LBool需要使用gopher-lua中预定义类型进行比较
lv := L.Get(-1) // get the value at the top of the stack
if lv == lua.LTrue { // correct
}
if bl, ok := lv.(lua.LBool); ok && bool(bl) { // wrong
}
lua调用golang
注册函数
func Double(L *lua.LState) int {
lv := L.ToInt(1) /* get argument */
L.Push(lua.LNumber(lv * 2)) /* push result */
return 1 /* number of results */
}
func main() {
L := lua.NewState()
defer L.Close()
L.SetGlobal("num", lua.LNumber(2))
L.SetGlobal("double", L.NewFunction(Double)) /* Original lua_setglobal uses stack... */
if err := L.DoString(`print(double(num))`); err != nil {
panic(err)
}
}
自定义模块
func Loader(L *lua.LState) int {
// register functions to the table
mod := L.SetFuncs(L.NewTable(), exports)
// register other stuff
L.SetField(mod, "name", lua.LString("value"))
L.Push(mod)
return 1
}
var exports = map[string]lua.LGFunction{
"myfunc": myfunc,
}
func myfunc(L *lua.LState) int {
return 0
}
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("mymodule", Loader)
if err := L.DoString(`
local m = require("mymodule")
m.myfunc()
print(m.name)`); err != nil {
panic(err)
}
}
GO调用lua
func main() {
L := lua.NewState()
defer L.Close()
if err := L.DoFile("module.lua"); err != nil {
panic(err)
}
if err := L.CallByParam(lua.P{
Fn: L.GetGlobal("double"),
NRet: 1,
Protect: true,
}, lua.LNumber(10)); err != nil {
panic(err)
}
ret := L.Get(-1) // returned value
fmt.Println(ret.String())
L.Pop(1) // remove received value
}
module.lua
function double(x)
return x*2
end
coroutines
co, _ := L.NewThread() /* create a new thread */
fn := L.GetGlobal("coro").(*lua.LFunction) /* get function from lua */
for {
st, err, values := L.Resume(co, fn)
if st == lua.ResumeError {
fmt.Println("yield break(error)")
fmt.Println(err.Error())
break
}
for i, lv := range values {
fmt.Printf("%v : %v\n", i, lv)
}
if st == lua.ResumeOK {
fmt.Println("yield break(ok)")
break
}
}
context
func main() {
L := lua.NewState()
defer L.Close()
ctx, cancel := context.WithCancel(context.Background())
L.SetContext(ctx)
defer cancel()
go func() {
err := L.DoString(`
i = 0
while true
do
i = i + 1
print(i)
end`)
if err!= nil {
fmt.Println(err.Error())
}
}()
cancel() // cancel the parent context
}
提前编译
// compiles it.
func CompileLua(script string) (*lua.FunctionProto, error) {
reader := strings.NewReader(script)
chunk, err := parse.Parse(reader, filePath)
if err != nil {
return nil, err
}
proto, err := lua.Compile(chunk, filePath)
if err != nil {
return nil, err
}
return proto, nil
}
// DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent
// to calling DoFile on the LState with the original source file.
func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error {
lfunc := L.NewFunctionFromProto(proto)
L.Push(lfunc)
return L.PCall(0, lua.MultRet, nil)
}
// Example shows how to share the compiled byte code from a lua script between multiple VMs.
func main() {
codeToShare := CompileLua("mylua.lua")
a := lua.NewState()
b := lua.NewState()
c := lua.NewState()
DoCompiledFile(a, codeToShare)
DoCompiledFile(b, codeToShare)
DoCompiledFile(c, codeToShare)
}
不支持的函数
string.dump
os.setlocale
lua_Debug.namewhat
package.loadlib
- debug hooks