使用预定义方法声明Lua类的golua

我正在尝试使用golua软件包为我的Go应用程序构建扩展API。我的想法是将几个类公开到lua VM中,例如Book类:

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.Value类型调用reflect.Value.Type

我的问题

1.如何创建与A Simplified Way to Declare Lua Classes中描述的相等的lua类?

2.如何向类添加“幻术方法”,例如__tostring 在此处

点赞
用户3586583
用户3586583

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

看一下我在这里找到的一个例子 https://github.com/stevedonovan/luar/blob/master/luar.go#L52

这里重要的是,当一个userdata或任何对象被创建时(你的书),你需要获取全局元表,然后用 L.SetMetaTable(-2) 将其设置为元表。

2016-01-17 23:15:32
用户1011543
用户1011543

在阅读 Programming in Lua 的第28章“C语言中的用户定义类型”以及 @Rochet2 的回答之后,我想出了一个可行的解决方案。我对Lua一无所知,对Go的了解也很少,所以我的结论可能是错误的。

这本 Programming in Lua 的版本是为Lua 5.0编写的,golua目前使用的是Lua 5.1。


BookCreate 函数

我们创建新的 userdata 而不是将普通Go struct 推入栈中。然后我们将新创建的 bookmetatable 设置为 "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 结构体的指针,因此如果要防止空指针/其他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 并使其成为自己的 _metatable_。我们添加了两个方法 Create__tostring 并将 "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")

我希望有人会发现这个有用。完整代码在这里

2016-01-18 16:09:08