【问题标题】:golua - declaring lua class with defined methodsgolua - 用定义的方法声明 lua 类
【发布时间】:2016-01-19 00:09:08
【问题描述】:

我正在尝试使用 golua package 为我用 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: call of reflect.Value.Type on zero Value

我的问题

  1. 如何创建与A Simplified Way to Declare Lua Classes 中描述的类等效的 lua 类?
  2. 如何将“魔术方法”添加到__tostringhere 等类中

【问题讨论】:

    标签: go lua


    【解决方案1】:

    我没有使用过 go,但您似乎从未将 Book 设置为您创建的新书的元表。我相当肯定这不会自动发生。

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

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

    【讨论】:

    • 你是对的!我花了一些时间,但我想我终于弄清楚了。我会为后代总结并发布我的解决方案......谢谢@rochet2
    【解决方案2】:

    @Rochet2 的回答和阅读Chapter 28. User-Defined Types in CProgramming in Lua 之后,我想出了可行的解决方案。我对 Lua 一无所知,对 Go 了解一点,所以我的结论可能是错误的。

    此版本的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”元表并使其自身成为自己的元表。我们添加两个方法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")
    

    我希望有人会发现它有用。 Full code here.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      相关资源
      最近更新 更多