gopher-luar: Index | Examples | Files

package luar

import ""

Package luar provides custom type reflection to gopher-lua.


This package is currently in development, and its behavior may change. This message will be removed once the package is considered stable.

Basic types

Go bool, number types, string types, and nil values are converted to the equivalent Lua type.


New(L, "Hello World")        =  lua.LString("Hello World")
New(L, uint(834))            =  lua.LNumber(uint(834))
New(L, map[string]int(nil))  =  lua.LNil


Channels have the following methods defined:

receive():    Receives data from the channel. Returns nil plus false if the
              channel is closed.
send(data):   Sends data to the channel.
close():      Closes the channel.

Taking the length (#) of a channel returns how many unread items are in its buffer.


ch := make(chan string)
L.SetGlobal("ch", New(L, ch))
ch:receive()      -- equivalent to v, ok := ch
ch:send("hello")  -- equivalent to ch <- "hello"
ch:close()        -- equivalent to close(ch)


Functions can be converted and called from Lua. The function arguments and return values are automatically converted from and to Lua types, respectively (see exception below).


fn := func(name string, age uint) string {
  return fmt.Sprintf("Hello %s, age %d", name, age)
L.SetGlobal("fn", New(L, fn))
print(fn("Tim", 5)) -- prints "Hello Tim, age 5"

A function that has the signature func(*luar.LState) int can bypass the automatic argument and return value conversion (see luar.LState documentation for example).

A special conversion case happens when function returns a lua.LValue slice. In that case, luar automatically unpacks the slice.


fn := func() []lua.LValue {
  return []lua.LValue{lua.LString("Hello"), lua.LNumber(2.5)}
L.SetGlobal("fn", New(L, fn))
x, y = fn()
print(x) -- prints "Hello"
print(y) -- prints "2.5"


Maps can be accessed and modified like a normal Lua table. The map's length can also be queried using the # operator.

Rather than using Lua's pairs function to create an map iterator, calling the value (e.g. map_variable()) returns an iterator for the map.


places := map[string]string{
  "NA": "North America",
  "EU": "European Union",
L.SetGlobal("places", New(L, places))
print(#places)       -- prints "2"
print(places.NA)     -- prints "North America"
print(places["EU"])  -- prints "European Union"
for k, v in places() do  -- prints all keys and values of places
  print(k .. ": " .. v)


Like maps, slices be indexed, be modified, and have their length queried. Additionally, the following methods are defined for slices:

append(items...):   Appends the items to the slice. Returns a slice with
                    the items appended.
capacity():         Returns the slice capacity.

For consistency with other Lua code, slices use one-based indexing.


letters := []string{"a", "e", "i"}
L.SetGlobal("letters", New(L, letters))
letters = letters:append("o", "u")

Like maps, calling a slice (e.g. slice()) returns an iterator over its values.


Arrays can be indexed and have their length queried. Only pointers to arrays can their contents modified.

Like slices and maps, calling an array (e.g. array()) returns an iterator over its values.


var arr [2]string
L.SetGlobal("arr", New(L, &arr))
arr[1] = "Hello"
arr[2] = "World"


Structs can have their fields accessed and modified and their methods called.


type Person {
  Name string
func (p Person) SayHello() {
  fmt.Printf("Hello, %s\n", p.Name)

tim := Person{"Tim"}
L.SetGlobal("tim", New(L, tim))
tim:SayHello() -- same as tim:sayHello()

By default, the name of a struct field is determined by its tag:

"":   the field is accessed by its name and its name with a lowercase
      first letter
"-":  the field is not accessible
else: the field is accessed by that value


type Person struct {
  Name   string `luar:"name"`
  Age    int
  Hidden bool   `luar:"-"`
Person.Name   -> "name"
Person.Age    -> "Age", "age"
Person.Hidden -> Not accessible


Pointers can be dereferenced using the unary minus (-) operator.


str := "hello"
L.SetGlobal("strptr", New(L, &str))
print(-strptr) -- prints "hello"

The pointed to value can changed using the pow (^) operator.


str := "hello"
L.SetGlobal("strptr", New(L, &str))
print(str^"world") -- prints "world", and str's value is now "world"

Pointers to struct and array values are returned when accessed via a struct field, array index, or slice index.

Type methods

Any array, channel, map, slice, or struct type that has methods defined on it can be called from Lua.

On maps with key strings, map elements are returned before type methods.


type mySlice []string
func (s mySlice) Len() int {
    return len(s)

var s mySlice = []string{"Hello", "world"}
L.SetGlobal("s", New(L, s))
print(s:len()) -- prints "2"

Lua to Go conversions

The Lua types are automatically converted to match the output Go type, as described below:

Lua type    Go kind/type
LBool       bool
            string ("true" or "false")
LChannel    chan lua.LValue
LNumber     numeric value
            string (strconv.Itoa)
LFunction   func
LNilType    chan, func, interface, map, ptr, slice, unsafe pointer
LState      *lua.LState
LString     string
LTable      slice
LUserData   underlying lua.LUserData.Value type

Example creating a Go slice from Lua:

type Group struct {
    Names []string

g := new(Group)
L.SetGlobal("g", luar.New(L, g))
g.Names = {"Tim", "Frank", "George"}

New types

Type constructors can be created using NewType. When called, it returns a new variable which is of the same type that was passed to NewType. Its behavior is dependent on the kind of value passed, as described below:

Kind      Constructor arguments          Return value
Channel   Buffer size (opt)              Channel
Map       None                           Map
Slice     Length (opt), Capacity (opt)   Slice
Default   None                           Pointer to the newly allocated value


type Person struct {
  Name string
L.SetGlobal("Person", NewType(L, Person{}))
p = Person()
p.Name = "John"
print("Hello, " .. p.Name)  // prints "Hello, John"

Thread safety

This package accesses and modifies the Lua state's registry. This happens when functions like New are called, and potentially when luar-created values are used. It is your responsibility to ensure that concurrent access of the state's registry does not happen.



Package Files

array.go cache.go chan.go config.go doc.go func.go luar.go map.go metatable.go ptr.go slice.go struct.go type.go util.go

func New Uses

func New(L *lua.LState, value interface{}) lua.LValue

New creates and returns a new lua.LValue for the given value.

The following table shows how Go types are converted to Lua types:

Kind            gopher-lua Type  Custom Metatable
nil             LNil             No
Bool            LBool            No
Int             LNumber          No
Int8            LNumber          No
Int16           LNumber          No
Int32           LNumber          No
Int64           LNumber          No
Uint            LNumber          No
Uint8           LNumber          No
Uint16          LNumber          No
Uint32          LNumber          No
Uint64          LNumber          No
Uintptr         *LUserData       No
Float32         LNumber          No
Float64         LNumber          No
Complex64       *LUserData       No
Complex128      *LUserData       No
Array           *LUserData       Yes
Chan            *LUserData       Yes
Func            *LFunction       No
Map             *LUserData       Yes
Ptr             *LUserData       Yes
Slice           *LUserData       Yes
String          LString          No
Struct          *LUserData       Yes
UnsafePointer   *LUserData       No

func NewType Uses

func NewType(L *lua.LState, value interface{}) lua.LValue

NewType returns a new type creator for the given value's type.

When the returned lua.LValue is called, a new value will be created that is the same type as value's type.


L := lua.NewState()
defer L.Close()

type Song struct {
    Title  string
    Artist string

L.SetGlobal("Song", NewType(L, Song{}))
		s = Song()
		s.Title = "Montana"
		s.Artist = "Tycho"
		print(s.Artist .. " - " .. s.Title)


Tycho - Montana

type Config Uses

type Config struct {
    // The name generating function that defines under which names Go
    // struct fields will be accessed.
    // If nil, the default behaviour is used:
    //   - if the "luar" tag of the field is "", the field name and its name
    //     with a lowercase first letter is returned
    //  - if the tag is "-", no name is returned (i.e. the field is not
    //    accessible)
    //  - for any other tag value, that value is returned
    FieldNames func(s reflect.Type, f reflect.StructField) []string

    // The name generating function that defines under which names Go
    // methods will be accessed.
    // If nil, the default behaviour is used:
    //   - the method name and its name with a lowercase first letter
    MethodNames func(t reflect.Type, m reflect.Method) []string
    // contains filtered or unexported fields

Config is used to define luar behaviour for a particular *lua.LState.

func GetConfig Uses

func GetConfig(L *lua.LState) *Config

GetConfig returns the configuration options for the given *lua.LState.

type LState Uses

type LState struct {

LState is an wrapper for gopher-lua's LState. It should be used when you wish to have a function/method with the standard "func(*lua.LState) int" signature.


const code = `
	print(sum(1, 2, 3, 4, 5))

L := lua.NewState()
defer L.Close()

sum := func(L *LState) int {
    total := 0
    for i := 1; i <= L.GetTop(); i++ {
        total += L.CheckInt(i)
    return 1

L.SetGlobal("sum", New(L, sum))

if err := L.DoString(code); err != nil {



type Metatable Uses

type Metatable struct {

Metatable holds the Lua metatable for a Go type.

func MT Uses

func MT(L *lua.LState, value interface{}) *Metatable

MT returns the metatable for value's type. nil is returned if value's type does not use a custom metatable.

Package luar imports 6 packages (graph) and is imported by 10 packages. Updated 2017-06-24. Refresh now. Tools for package owners.