Skip to content

gopher-lua

Kho lưu trữ: yuin/gopher-lua: GopherLua: VM and compiler for Lua in Go (github.com)

Tài liệu: gopher-lua/README.rst at master · yuin/gopher-lua (github.com)

Giới thiệu

GopherLua là máy ảo và trình biên dịch lua được viết bằng go, sử dụng GoAPI để nhúng script lua vào chương trình Go và thao tác lua bằng GoAPI. Lua là một ngôn ngữ script nhỏ gọn và mạnh mẽ, rất được ưa chuộng trong phát triển game, vì vậy các ứng dụng máy chủ game thường sử dụng nhiều, khi cần tương tác với lua, thư viện này có thể dễ dàng tương tác giữa Go và lua.

Cài đặt

go get github.com/yuin/gopher-lua

WARNING

Chỉ hỗ trợ phiên bản Go1.19 trở lên

Bắt đầu nhanh

Tải file lua

go
package main

import (
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  if err := L.DoFile("hello.lua"); err != nil {
    panic(err)
  }
}

Hoặc dưới dạng chuỗi trực tiếp

go
package main

import (
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  if err := L.DoString(`print("hello")`); err != nil {
      panic(err)
  }
}

Gọi hàm Lua từ Go

go
package main

import (
    "fmt"
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Thực thi script lua
  if err := L.DoString(`
    function add(a, b)
      return a + b
    end
  `); err != nil {
    panic(err)
  }
  
  // Gọi hàm lua
  if err := L.CallByParam(lua.P{
    Fn:      L.GetGlobal("add"),
    NRet:    1,
    Protect: true,
  }, lua.LNumber(10), lua.LNumber(20)); err != nil {
    panic(err)
  }
  
  // Lấy kết quả
  ret := L.Get(-1)
  fmt.Printf("Kết quả: %v\n", ret)
  
  L.Pop(1) // Loại bỏ kết quả khỏi stack
}

Truyền dữ liệu từ Go sang Lua

go
package main

import (
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Đặt biến cho lua
  L.SetGlobal("name", lua.LString("Go Developer"))
  L.SetGlobal("version", lua.LNumber(1.0))
  
  if err := L.DoString(`
    print("Xin chào từ", name)
    print("Phiên bản:", version)
  `); err != nil {
    panic(err)
  }
}

Đăng ký hàm Go cho Lua

go
package main

import (
    "fmt"
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Đăng ký hàm Go
  L.SetGlobal("goPrint", L.NewFunction(func(L *lua.LState) int {
    msg := L.ToString(1)
    fmt.Println("Go nhận được:", msg)
    return 0
  }))
  
  // Gọi từ lua
  if err := L.DoString(`
    goPrint("Xin chào từ Lua!")
  `); err != nil {
    panic(err)
  }
}

Làm việc với Table

go
package main

import (
    "fmt"
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Tạo table
  table := L.NewTable()
  table.RawSetString("name", lua.LString("test"))
  table.RawSetString("value", lua.LNumber(42))
  
  L.SetGlobal("config", table)
  
  if err := L.DoString(`
    print("Tên:", config.name)
    print("Giá trị:", config.value)
  `); err != nil {
    panic(err)
  }
  
  // Đọc table từ lua
  if err := L.DoString(`
    data = {
      items = {"item1", "item2", "item3"}
    }
  `); err != nil {
    panic(err)
  }
  
  data := L.GetGlobal("data").(*lua.LTable)
  items := data.RawGetString("items").(*lua.LTable)
  
  items.ForEach(func(key, value lua.LValue) {
    fmt.Printf("Item: %v\n", value)
  })
}

Xử lý lỗi

go
package main

import (
    "fmt"
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Bẫy lỗi
  if err := L.DoString(`
    error("Đây là một lỗi!")
  `); err != nil {
    fmt.Println("Bắt được lỗi:", err)
  }
  
  // Sử dụng pcall
  if err := L.DoString(`
    local status, err = pcall(function()
      error("Lỗi trong pcall")
    end)
    print("Status:", status, "Error:", err)
  `); err != nil {
    fmt.Println("Lỗi:", err)
  }
}

Module và Package

go
package main

import (
    "github.com/yuin/gopher-lua"
)

func main() {
  L := lua.NewState()
  defer L.Close()
  
  // Tạo module
  mod := L.NewTable()
  mod.RawSetString("version", lua.LString("1.0"))
  mod.RawSetString("hello", L.NewFunction(func(L *lua.LState) int {
    fmt.Println("Xin chào từ module!")
    return 0
  }))
  
  // Đăng ký module
  L.SetGlobal("mymodule", mod)
  
  if err := L.DoString(`
    print("Phiên bản module:", mymodule.version)
    mymodule.hello()
  `); err != nil {
    panic(err)
  }
}

Best Practices

  1. Quản lý bộ nhớ: Luôn đóng LState bằng defer L.Close()
  2. Xử lý lỗi: Kiểm tra lỗi sau mỗi lần gọi DoString hoặc DoFile
  3. Type assertion: Sử dụng type assertion an toàn khi lấy giá trị từ Lua
  4. Performance: Tái sử dụng LState khi có thể để giảm overhead
  5. Bảo mật: Không thực thi code lua từ nguồn không đáng tin cậy

Kết luận

GopherLua là một thư viện mạnh mẽ để tích hợp Lua vào ứng dụng Go. Với khả năng gọi hàm qua lại giữa Go và Lua, xử lý table, và đăng ký module, bạn có thể tạo ra các ứng dụng linh hoạt với khả năng script hóa cao.

Golang by www.golangdev.cn edit