How to use lua for extended details in Golang

  • 2020-06-07 04:38:55
  • OfStack

preface

Recently, I need to use lua for extension in my project. I found that there is an lua virtual machine written with golang on github, named ES8en-ES9en. It is not bad after use, so I would like to share it with you.

The data type

Data types in lua correspond to data types in golang as the authors have documented. It is worth noting that the type begins with L and the type name begins with LT.

Data in golang to data in lua must be converted to the type beginning with L:


str := "hello"
num := 10
L.LString(str)
L.LNumber(float64(num))

Data in lua is converted to data in golang. The project provides functions such as ToInt and CheckString for conversion. However, the type must be known in advance.


value := L.Get(1)
switch value.Type() {
case lua.LTString:
case lua.LTTable:
....
}

You can also use ES35en-ES36en for easy type conversion.

golang and lua call each other's functions

The function in golang must be converted to func(L * lua.State) in order to be injected into lua, the return parameter int represents the number of return parameters.


func hello(L *lua.State) int {
  // Push the return parameter onto the stack 
  L.Push(lua.LString("hello"))
  // The return parameter is 1 a 
  return 1
}
// injection lua In the 
L.SetGlobal("hello", L.NewFunction(hello))

Call the lua function in golang. The lua script defines the function first and then calls CallByParam to make the call:


// First get lua Functions defined in 
fn := L.GetGlobal("hello")
if err := L.CallByParam(lua.P{
 Fn: fn,
 NRet: 1,
 Protect: true,
 }, lua.LNumber(10)); err != nil {
 panic(err)
}
// Gets the function return value here 
ret := L.Get(-1)

Table

table in lua is a very powerful thing, and the project also supports many methods for table, such as getting 1 field and adding 1 field. It is recommended to use gluamapper to convert tabl to the structure of golang or map[string]interface{}.


type Role struct {
 Name string
}

type Person struct {
 Name  string
 Age  int
 WorkPlace string
 Role  []*Role
}

L := lua.NewState()
if err := L.DoString(`
person = {
 name = "Michel",
 age = "31", -- weakly input
 work_place = "San Jose",
 role = {
 {
  name = "Administrator"
 },
 {
  name = "Operator"
 }
 }
}
`); err != nil {
 panic(err)
}
var person Person
if err := gluamapper.Map(L.GetGlobal("person").(*lua.LTable), &person); err != nil {
 panic(err)
}
fmt.Printf("%s %d", person.Name, person.Age)

Module loading and use

Project provides lua basic module, called OpenLibs can load these modules, including io, math, os, debug etc. If you want to skip loading can use SkipOpenLibs parameters.

If you want to develop your own library, the documentation also says:


func Loader(L *lua.LState) int {
 // Register the export function in the module 
 mod := L.SetFuncs(L.NewTable(), exports)
 L.Push(mod)
 return 1
}

var exports = map[string]lua.LGFunction{
 "myfunc": myfunc,
}

func myfunc(L *lua.LState) int {
 return 0
}
// I can load it here mymodule The module 
L.PreloadModule("mymodule", mymodule.Loader)

conclusion

Of course, there is only a brief introduction to the basic usage, and there are some unsupported areas in the project, such as: package.loadlib.


Related articles: