我正在尝试使用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
__tostring
here 答案 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 C的Programming 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