This is a creation in Article, where the information may have evolved or changed.
There is a need to use the go language to implement some basic modules, using LUA to implement basic logic, so there is the need to invoke the Go function in Lua.
There is very little data on go, but the go can embed the C language, making this implementation feasible. Finally, the full userdata in Lua was used to implement this thing. The functions in Go are all encapsulated into UserData for Lua to invoke. This is possible, since UserData can be set metatable,metatable within can set an original method __call, then the following call:
It can become
func.metatable.__call(func, 1, 3)
As long as we implement such a meta-method in C, loading the specific metatable, and setting this metatable as the metatable of the function UserData, we can implement this requirement.
All calls in the Lua script will be called to the C code part of Go, in C function, this UserData parse, determine to a go function, then in go to call the Go language part, then lua-"Go" bridge has been opened.
So, we can define a structure in go
type LuaGo_State struct { ....BasePart gofunctions map[int]interface{} baseSeq int}
Some of the basic LUA operations should have been implemented in Basepart, such as creating something, and I'm not going to post it. Baseseq is the ordinal of the exported gofunction, which is used to determine the callback's go function. The Gofunctions records the corresponding gofunction of an ordinal number.
Then, we need to record the corresponding luago_state in the lua_state in the lua_state.
// 开启gofunction注册支持func (this *LuaGo_State) LuaGo_OpenInvokeCompenent() { // 初始化导出map C.luago_open(this.handle, unsafe.Pointer(this)) this.gofunctions = make(map[int]interface{}) this.baseSeq = 1}
So we're going to press the luago_state in the C code.
The next step is to register a go function, and each go function corresponds to a sequence within a luago_state, then make a record in the map, and then register it in the C code.
// 压入gofunctionfunc (this *LuaGo_State) LuaGo_PushGoFunction(_name string, _func LuaGo_Function) int { funcSeq := this.luago_getGoFunctionSeq() this.gofunctions[funcSeq] = _func // 注册到lua中 cfuncname := C.CString(_name) C.luago_pushGoFunction(this.handle, cfuncname, C.int(funcSeq)) C.free(unsafe.Pointer(cfuncname)) return funcSeq}
In C code, the idea is to create a userdata,userdata value for this go function is its ordinal number, and then set the above MetaTable, recorded in the Lua_state global variables. The original method in C is called when a function call is made in Lua.
// 元方法static int luago_metamethod_call(struct lua_State* L){ // stack userdata, parameters... if(lua_isuserdata(L, 1)) { // check valid int* pUserData = (int*)luaL_checkudata(L, 1, g_szGoMetaTable); if(0 != pUserData) { int nGoFunctionSeq = *pUserData; // get the golua_state void* pLuaGoState = luago_getGoLuaState(L); // call go callback return (int)luago_call(pLuaGoState, nGoFunctionSeq); } else { luaL_argcheck(L, pUserData != 0, 1, "GoFunction expected"); } } luago_error(L, "trying to call a non-callable object"); return 0;}
This is also very simple, take the userdata sequence out, call the go callback function, in go through this sequence to find the corresponding function, call this function.
Github:luago