github.com/yuin/gopher-lua 踩坑日记

本文主要记录下在日常开发过程中, 使用 github.com/yuin/gopher-lua 过程中需要注意的地方。

后续遇到其他的需要注意的事项再补充。

1、加载LUA_PATH环境变量

在实际开发中,我们会将一些公共的、可重复使用的代码封装起来,假如我们只是一些简单的处理,全部写在一个文件是没有问题的,维护起来也并不是很麻烦。但是当我们的需求变得复杂起来,或者需求调整的时候,我们还是将所有功能都写在同一个文件的时候,就变得不合理起来,后期的维护更是灾难性的,这个时候就需要将一些公共的、重复使用的代码,抽离出来,根据功能的不同分类,当做一个个模块,在使用的时候使用 require 导入进来,这样才合理。

既然我们需要将自定义的 module 导入进来,那么我们肯定是需要设计环境变量的。

最重要的地方就是下面这点:

// 重点就是这句, 先设置环境变量, 再创建 lua 的 虚拟机, 这样环境变量才生效!!! setLuaLibPath() lvm := newLuaVm(pluginPath, context.Background()) 

接下来再详细看演示的demo。

先看看代码目录分层,有一个整体认识。

--go_call_lua_test |---go.mod |---main.go |---plugin.lua |---lib/lua/test.lua 

main.go 代码

package main  import ( 	"context" 	"errors" 	"fmt" 	lua "github.com/yuin/gopher-lua" 	"go.uber.org/atomic" 	luar "layeh.com/gopher-luar" 	"os" 	"path/filepath" )  func getExeDir() (string, string) { 	exePath, _ := os.Executable() 	exeDir, exeName := filepath.Split(exePath) 	return exeDir, exeName }  func absPath(fp string) string { 	exeAbsDir, _ := getExeDir() 	//绝对路径 	if !filepath.IsAbs(fp) { 		return filepath.Join(exeAbsDir, fp) 	} else { 		return fp 	} }  func setLuaLibPath() { 	//设置lua环境变量 	pathStr := "" 	LuaLibPath := []string{"./lib/lua/?.lua"} 	for _, path := range LuaLibPath { 		pathStr += ";" + absPath(path) 	} 	pathStr += ";;" 	os.Setenv("LUA_PATH", pathStr) }  type LuaVm struct { 	*lua.LState 	path   string 	Loaded atomic.Bool }  func newLuaVm(path string, ctx context.Context) *LuaVm { 	lv := &LuaVm{ 		path:   path, 		LState: lua.NewState(), 	} 	lv.SetContext(ctx) 	if err := lv.load(); err != nil { 		panic(fmt.Errorf("lvm error=%s", err)) 	} 	return lv }  func (lv *LuaVm) load() error { 	//加载工具 下面是将 go 提供的功能当做模块 给 lua 使用 	//lv.SetGlobal("FILE", luar.New(lv.LState, &test.FileTool{}))  	if len(lv.path) == 0 { 		return fmt.Errorf("plugin file empty") 	} 	if err := lv.DoFile(lv.path); err != nil { 		return err 	}  	lv.Loaded.Store(true) 	return nil }  func (lv *LuaVm) CallLua() (result string, err error) {  	if err := lv.CallByParam(lua.P{ 		Fn:      lv.GetGlobal("PluginTest"), 		NRet:    2, 		Protect: true, 	}, luar.New(lv.LState, "I'm coming go!")); err != nil { 		fmt.Printf("PrimaryIn error=%s", err) 	} 	retCode, _ := lv.Get(-1).(lua.LNumber) 	lv.Pop(1)  	retPkt, _ := lv.Get(-1).(lua.LString) 	lv.Pop(1)  	if retCode != 0 { 		return "", errors.New("untreated") 	}  	return string(retPkt), nil }  func main() { 	pluginPath := "./plugin.lua"  	// 重点就是这句, 先设置环境变量, 再创建 lua 的 虚拟机, 这样环境变量才生效!!! 	setLuaLibPath() 	lvm := newLuaVm(pluginPath, context.Background())  	ret, err := lvm.CallLua() 	fmt.Println("ret --> ", ret) 	fmt.Println("err --> ", err) }  

plugin.lua 代码

local TestLib = require("test")  function PluginTest(param)     print(param)     print("coming PluginTest")     TestLib.CallTestFunc()      return "I'm coming lua!" end 

test.lua 代码

justTest = {}  function justTest.CallTestFunc()     print("coming justTest.CallTestFunc") end  -- 一定要 return, 否则不生效 return justTest 

编译后执行结果:

I'm coming go! coming PluginTest coming justTest.CallTestFunc ret -->  I'm coming lua!     err -->  <nil>  

发表评论

评论已关闭。

相关文章