Go 有一个开源的 Excelize 很强大,可用于操作 Excel 表格。
看着 Excelize 范例里丝滑的 Go 代码,我就想着怎么能弄到 aardio 里用。先尝试把 Go 对象封包到 IDispatch 接口,然后又用 Go 反射整了几个小时,最后都放弃了。
后面继续调整思路,改为调用在运行时用 Go 语法写脚本的 Yaegi (不需要安装 Go 编译环境,体积小速度快,内存加载没有外部依赖 ),一顿封装实现了在 aardio 里运行时执行 Go 代码、读写 Go 变量、调用 Go 函数。
一、 aardio 运行 Yaegi(Go 脚本)
aardio 代码示例:
//创建 Yaegi(Go 脚本)解释器 import golang.yaegi; var go = golang.yaegi(); //直接用 Go 语法写脚本。 go.eval(` package main //导入内建模块 import "fmt" //编写函数 func Hello(name string) string { return name; } //全局变量 var GlobaVal = "这是全局变量"; `) //在 aardio 中直接调用 Go 函数 var ret = go.Hello( "Hello" ); //在 aardio 中修改 Go 全局常量的值 go.GlobaVal = "新的 Go 全局常量值"; import console.int; //获取 Go 全局常量的值 console.log( go.GlobaVal );
二、调用 Excelize 操作 Excel 表格
然后调用 Excelize 就变简单了。
基于上面的原理,我又写了一个 golang.excelize 扩展库。然后只要直接复制粘贴 Excelize 官方的 Go 代码范例就可以在 aardio 里用了。
直接看 aardio 代码:
import console.int; import golang.excelize; var go = golang.excelize(); //直接用 Go 语法写脚本。 go.eval(` package main import ( "fmt" //golang.excelize 已经提前导入,不用再下载安装外部模块 "github.com/xuri/excelize/v2" ) func CreateExcel(path string) string { //下面是 Excelize 官网范例 f := excelize.NewFile(); defer func() { if err := f.Close(); err != nil { fmt.Println(err) } }() // 创建新表格. index, err := f.NewSheet("Sheet2") if err != nil { fmt.Println(err) return "" } // 设置单格的值. f.SetCellValue("Sheet2", "A2", "Hello world.") f.SetCellValue("Sheet1", "B2", 100) // 设置工作簿的当前激活表格 f.SetActiveSheet(index) // 保存表格到指定的路径 if err := f.SaveAs(path); err != nil { fmt.Println(err) } //读单格的值 cell, err := f.GetCellValue("Sheet1", "B2") if err != nil { fmt.Println(err) return "" } return cell; }`) //在 aardio 中直接调用 Go 函数 var ret = go.CreateExcel( io.fullpath("/hello.xlsx") ); //查看 Go 函数的返回值 console.log( ret );
三、Yaegi 导入第三方模块
这里说一下 Yaegi 导入第三方模块的步骤。
以 aardio 中的 golang.excelize 扩展库为例。打开生成 DLL 的源文件:
"~\lib\golang\excelize\.dll\编译.aardio"
然后在 Go 源码里可以看到这个全局常量:
var Symbols = map[string]map[string]reflect.Value{}
这个 Symbols 就是符号表,第三方模块都放到这里面。
例如我们要添加 aardio 模块,在创建解释器以后就这么写:
//创建 Yaegi 解释器 yaegiInterpreter = interp.New(interp.Options{}) yaegiInterpreter.Use(stdlib.Symbols) //添加第三方模块 Symbols["aardio/aardio"] = map[string]reflect.Value{ "Call": reflect.ValueOf(aardio.Call), "CallPtr": reflect.ValueOf(aardio.CallPtr), "CallJson": reflect.ValueOf(aardio.CallJson), "JsonParam": reflect.ValueOf(aardio.JsonParam), } //注册到解释器 yaegiInterpreter.Use(Symbols);
Symbols 可以理解为 aardio 里的表对象,每个键值对注册一个第三方模块。比较坑的地方是这个键名 "aardio/aardio" 要写两次。
如果是非常大的模块,手动写就不现实了。这时候可以用 Yaegi 提供的工具自动生成符号表。为了避免被坑,可以直接运行我提供的 aardio 代码生成,以 Excelize 为例:
//提取符号表 import console.int; import golang; var go = golang("/","1.22.3") go.mod("init excelize") go.get("github.com/xuri/excelize/v2") go.yaegiExtract("github.com/xuri/excelize/v2")
没有任何显示是正常的,耐心等到完成。打开自动生成的
github_com-xuri-excelize-v2.go
有了前面的知识,看生成的代码你就知道怎么做了。
四、Yaegi(Go 脚本)回调 aardio 函数
直接看代码:
//aardio 回调函数 import golang.yaegi; var go = golang.yaegi(); go.eval(` package main import "aardio" func TestCallBack(fnCallback float64) int{ var s = "字符串" var r,_ = aardio.CallJson( fnCallback ,s,123,map[string]int{"id": 1, "id2": 2} ) return r } `) import raw.jsonCall //创建回调函数指针, 在 Go 中必须用 aardio.CallJson 调用。 var callback = raw.jsonCall( function(a,b,c){ console.log("回调参数:",a,b) console.dumpJson(c); return 123; } ); import console.int var ret = go.TestCallBack( callback ) console.log(ret);
回调可以支持任意个数 JSON 兼容的参数,传参与返回值会自动通过 JSON 转换。
要注意在 aardio 中调用 Yaegi 函数时,数值默认是 float64 类型( JSON 只能描述一种数值类型 ),可以在 Go 函数里强制转换一下就可以了。
五、Yaegi(Go 脚本)调用 aardio 窗口函数
直接看代码:
import golang.yaegi; var go = golang.yaegi(); go.eval(` package main import "aardio" func TestCallBack(hwnd float64){ aardio.Call(hwnd,"onCallback","参数1","参数2"); } `) import win.ui; var winform = win.form(text="Yaegi") winform.add( edit={cls="edit";left=43;top=27;right=717;bottom=400;multiline=1;z=1} ) winform.onCallback = function(param1,param2){ winform.edit.print("Go 调用了 aardio 函数,参数:",param1,param2) } go.TestCallBack( winform.hwnd ); winform.show(); win.loopMessage();
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://sigusoft.com/goland/1172.html