今天來介紹一個比較特別的應用,就是如何在 golang 使用 lua ,這種的應用場景通常會在一個固定流程裡面,但裡面有不同的商業邏輯,用 OOP(Object-oriented programming) 的 pattern 來解釋就是所謂的工廠模式,裡面產生的東西會有不同的邏輯,那些邏輯很適合用 lua 去寫。

首先我們會需要可以在 golang 裡面執行 lua 的 package,那我個人蠻推薦這套的 yuin/gopher-lua

首先,先執行

go get go get github.com/yuin/gopher-lua

而且要 golang version 1.9 以上喔

再來,我們先來個 hello world

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

它也可以直接讀取一個 lua file

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

再來玩一個比較花俏一點的應用,在 lua 裡面呼叫 golang 定義好的 func,

有些應用下,讓 golang 來負責運算速度上會快很多,以我實務上的經驗,光是 each 陣列之類的應用,golang的速度都快上不少。雖然會需要消耗一點 golang 跟 lua 上面 type 轉換的消耗,但我覺得還是很值得這樣使用的。畢竟在一些效能上不用錙銖必較,反而是商業邏輯相當複雜比重又很高的應用場景,就是 lua 的戰場。

func Loader(L *lua.LState) int {
	mod := L.SetFuncs(L.NewTable(), exports)
	L.Push(mod)
	return 1
}

var exports = map[string]lua.LGFunction{
	"add": Add,
}

func Add(l *lua.LState) int {
    //lua 跟一般語言不一樣,他是 1 index base ,其他語言都是 0 index base,這邊在 lua array 存取上要注意! 都是由 1 開始喔
	x := l.ToInt(1)
	y := l.ToInt(2)


    //把回傳值依續傳回去
	l.Push(lua.LNumber(x + y))

    //這邊決定在 lua 裡面 回傳值數量
	return 1
}
func main() {
	L := lua.NewState()
	defer L.Close()

	//預載 func 到 lua runtime裡面
	L.PreloadModule("mathmodule", Loader)
	if err := L.DoFile("main.lua"); err != nil {
		panic(err)
	}
}

以上,需要更完整的說明可以到官網,上面的完整範例也都有在我個人的 github