• 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 -->   
    

    __EOF__

  • 本文作者: 画个一样的我
  • 本文链接: https://www.cnblogs.com/huageyiyangdewo/p/17671061.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Antiderivative
    Unity与IOS⭐一、百度语音IOS版Demo调试方法
    Go语言知识查漏补缺|基本数据类型
    记录crack某IDE插件过程
    HiveSQL中的JOIN ON条件
    java基于微信小程序的知识分享科普管理系统 uniapp小程序
    云扩研习社 | RPA高级开发技巧(上)
    【java】java 类型安全 与 unchecked warning
    f-string 格式化字符串的用法
    机器人操控电脑,华为天才少年稚晖君再出手,直呼:项目不太难
  • 原文地址:https://www.cnblogs.com/huageyiyangdewo/p/17671061.html