استدعاء وظائف لوا من .lua استخدام المقابض؟

StackOverflow https://stackoverflow.com/questions/3432231

  •  26-09-2019
  •  | 
  •  

سؤال

أنا أعمل في مشروع صغير أحاول دمج LUA مع C ++. مشكلتي هي كما يلي:

لدي العديد من البرامج النصية Lua ، دعنا ندعوها s1.lua s2.lua و s3.lua. لكل من هذه الوظائف التالية: setVars () و ExecuterEsults ().

أنا الآن قادر على الاتصال بملف LUA من خلال Lual_Dofile وبعد استخدام setVars () و/أو التنفيذ () مباشرة. لكن المشكلة هنا هي أنه بعد تحميل S2.lua لم يعد بإمكاني استدعاء وظائف S1.lua. هذا يعني أنني يجب أن أعيد إعادة lual_dofile على s1.lua لاستعادة الوصول إلى الوظيفة وبقيامك بذلك أفقد الوصول إلى الوظائف في S2.LUA.

هل هناك طريقة لتحميل جميع ملفات LUA على التوالي ، وبعد ذلك ابدأ في استدعاء وظائفها حسب الرغبة؟ شيء مثل s1-> eventireSults () S5-> eventireSults () S3-> setvars () إلخ.

لديّ بالفعل نظام معمول به في مكانه باستخدام نظام التشغيل :: نظام ملفات لاكتشاف جميع ملفات LUA في مجلد ، ثم أحفظ أسماء الملفات هذه في متجه ثم ببساطة تكرار عبر المتجه لتحميل كل ملف LUA في صف واحد.

إن ما يبتسم بملء المتجه مع ملفات LUA ، تبدو وظيفة تحميل المكون الإضافي مثل هذه في الوقت الحالي:

void Lua_plugin::load_Plugins(){
 std::vector<std::string>::const_iterator it;
 for (it=Lua_PluginList.begin(); it!=Lua_PluginList.end(); it++){
  std::cout<<"File loading: " << *it << std::endl;
  std::string filename =  *it;
  std::string filepath = scriptdir+filename;
  if (luaL_loadfile(L, filepath.c_str()) || lua_pcall(L, 0, 0, 0)) {
   std::cout << "ScriptEngine: error loading script. Error returned was: " << lua_tostring(L, -1) << std::endl;
  }
 }
}

لجعل الأمر أكثر وضوحًا ، كل ما لدي في .lua's هو شيء من هذا القبيل:

-- s1.lua

setVars()
--do stuff
end

executeResults()
--dostuff
end

إلخ ، لكني أود أن أكون قادرًا على استدعاء setvars s1.lua's () و s2.lua's setVars () بعد مجرد تحميل كل من على التوالي.

هل كانت مفيدة؟

المحلول

هذا بفعالية ماذا جويل مقترح باستخدام C API:

#include <stdio.h>

#include "lua.h"

static void
executescript(lua_State *L, const char *filename, const char *function)
{
    /* retrieve the environment from the resgistry */
    lua_getfield(L, LUA_REGISTRYINDEX, filename);

    /* get the desired function from the environment */
    lua_getfield(L, -1, function);

    return lua_call(L, 0, 0);
}

static void
loadscript(lua_State *L, const char *filename)
{
    /* load the lua script into memory */
    luaL_loadfile(L, filename);

    /* create a new function environment and store it in the registry */
    lua_createtable(L, 0, 1);
    lua_getglobal(L, "print");
    lua_setfield(L, -2, "print");
    lua_pushvalue(L, -1);
    lua_setfield(L, LUA_REGISTRYINDEX, filename);

    /* set the environment for the loaded script and execute it */
    lua_setfenv(L, -2);
    lua_call(L, 0, 0);

    /* run the script initialization function */
    executescript(L, filename, "init");
}

int
main(int argc, char *argv[])
{
    lua_State *L;
    int env1, env2;

    L = (lua_State *) luaL_newstate();
    luaL_openlibs(L);

    loadscript(L, "test1.lua");
    loadscript(L, "test2.lua");

    executescript(L, "test1.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test2.lua", "run");
    executescript(L, "test1.lua", "run");

    return 0;
}

اختبار البرامج النصية:

-- test1.lua
function init() output = 'test1' end
function run() print(output) end

-- test2.lua
function init() output = 'test2' end
function run() print(output) end

انتاج:

test1
test2
test2
test1

لقد حذفت كل الأخطاء في التعامل مع الإيجاز ، لكنك ستحتاج إلى التحقق من قيمة الإرجاع luaL_loadfile والاستخدام lua_pcall بدلاً من lua_call.

نصائح أخرى

ال setfenv() يمكن استخدام الوظيفة لإنشاء ملف صندوق الرمل أو بيئة لكل ملف تم تحميله.

يوضح هذا المثال أنه يمكن تحميل جميع الملفات الثلاثة مع وظائف متضاربة وأنه يمكن استدعاء الوظائف بأي ترتيب. يمكن كتابة رمز مماثل في C ++. هذا المثال يصدر وظيفة الطباعة فقط إلى كل بيئة ، قد تكون هناك حاجة إلى المزيد في السيناريو الخاص بك.

function newEnv()
  -- creates a simple environment
  return {["print"]=print}
end

local e={} -- environment table
local c    -- chunk variable

-- first instance
c = loadstring([[function f() print("1") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e]) -- set the loaded chunk's environment
pcall(c) -- process the chunk (places the function into the enviroment)

-- second instance
c = loadstring([[function f() print("2") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

-- third instance
c = loadstring([[function f() print("3") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

pcall(e[3].f) --> 3
pcall(e[2].f) --> 2
pcall(e[1].f) --> 1
pcall(e[1].f) --> 1
pcall(e[2].f) --> 2
pcall(e[3].f) --> 3

يمكنك إنشاء دولة جديدة lua_newstate() لكل ملف. سيكون هذا أسهل من إجابتي السابقة. ومع ذلك ، قد يكون لها عقوبة الأداء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top