golua - 使用已定义的方法声明lua类

时间:2016-01-17 18:07:49

标签: go lua

我正在尝试使用golua package为我用Go编写的应用程序构建扩展API。我的想法是将几个类暴露给lua VM,例如Book class:

local book = Book.Create("Le Petit Prince")
print(book)
book:save()

我现在能做的只是基本的:

type Book struct {
    Id int64
    Title string
}

func BookCreate(L *lua.State) int {
    title := L.ToString(1)
    p := &Book{Id: 1, Title: title}
    L.PushGoStruct(p)
    return 1
}

func BookToString(L *lua.State) int {
    book, _ := L.ToGoStruct(1).(*Book)
    L.PushString(fmt.Sprintf("Book(Id=%d, Title=\"%s\")", book.Id, book.Title))
    return 1
}

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

L.NewMetaTable("Book")
L.SetMetaMethod("Create", BookCreate)
L.SetMetaMethod("tostring", BookToString)
L.SetGlobal("Book")

这允许我这样做:

local book = Book.Create("Le Petit Prince")
print(Book.tostring(book))

但不是这样:

local book = Book.Create("Le Petit Prince")
print(book:tostring())

// reflect: call of reflect.Value.Type on zero Value

我的问题

  1. 如何创建与A Simplified Way to Declare Lua Classes中描述的lua类相同的lua类?
  2. 如何向__tostring here
  3. 等课程添加“魔术方法”

2 个答案:

答案 0 :(得分:1)

我没有使用go,但看起来你从未将Book设置为你创建的新书的元表。我相当确定这不会自动发生。

查看我在此处找到的示例https://github.com/stevedonovan/luar/blob/master/luar.go#L52

这里重要的是,当创建用户数据或任何对象(您的书)时,您需要获取全局元表,然后将其设置为元表L.SetMetaTable(-2)

答案 1 :(得分:0)

@Rochet2的回答之后,在阅读了Chapter 28. User-Defined Types in CProgramming in Lua之后,我提出了有效的解决方案。我对Lua一无所知,只关于Go,所以我的结论可能不对。

  

此版本的 Lua编程是为Lua 5.0编写的 - golua使用Lua 5.1(目前为止)。

BookCreate功能

我们创建新的 userdata ,而不是将普通的Go struct 推送到堆栈。然后我们将新创建的book metatable 设置为" Book"。

L.NewUserdata返回unsafe.Pointer,因此我们将其投放到Book

func BookCreate(L *lua.State) int {
    title := L.ToString(1)
    book := (*Book)(L.NewUserdata(uintptr(unsafe.Sizeof(Book{}))))

    L.LGetMetaTable("Book")
    L.SetMetaTable(-2)

    book.Id = 1;
    book.Title = title;

    return 1
}

BookToString功能

在这里,我们只需从堆栈中获取 userdata 并将其转换为Book

  

请注意,我们弹出堆栈的内容可能不是指向Book struct的指针,因此如果我们想要阻止nil指针/其他Go错误,则可能需要进行一些基本类型检查。

func BookToString(L *lua.State) int {
    book := (*Book)(L.ToUserdata(1))
    L.PushString(fmt.Sprintf("Book(Id=%d, Title=\"%s\")", book.Id, book.Title))

    return 1
}

main功能

我们初始化新的" Book" metatable并使自己成为自己的metatble。我们添加了两种方法Create__tostring,并制作了#34; Book"全球化。

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

L.NewMetaTable("Book")
L.PushString("__index")
L.PushValue(-2)
L.SetTable(-3)
L.SetMetaMethod("Create", BookCreate)
L.SetMetaMethod("__tostring", BookToString)
L.SetGlobal("Book")

这就是我们现在可以在Lua做的事情:

local book = Book.Create('Le Petit Prince')
print(book)
print(book:__tostring())
print(Book.__tostring(book))

--out:
Book(Id=1, Title="Le Petit Prince")
Book(Id=1, Title="Le Petit Prince")
Book(Id=1, Title="Le Petit Prince")

我希望有人会觉得它很有用。 Full code here