5

次のスクリプトを含む 2 つのスクリプト ファイルがあります。

//parent.lua
function scope()
    local var = "abc"

    require "child"
end

//child.lua
print(var)

このように、child.lua は nil 値を出力します。これは、parent.lua のスコープがそのローカル機能をモジュールに公開しないためです。このスコープ内で var の宣言の後に require ディレクティブが記述されているため、そうなると思いました。私の願いは、子のすべての線を親に事実上完全に注入することです。子スクリプトは、読みやすくするためにエクスポートされているだけです。ローカルスコープを渡すにはどうすればよいですか? loadfile() も dofile() も機能しませんでした。関数環境 fenv はローカル値を保持しません。debug.setlocal() は新しい変数を作成できないようです (また、子にレシーバーが必要になります)。スクリプトを再コンパイルする以外の方法はありますか?

4

1 に答える 1

2

少しの努力でできます。の変数childが実際の上位値である場合、それらを関数の値に「リンク」できますscope。それらがグローバル変数である場合 (ここではそのようです)、それらを使用して環境にマップし、setfenvその環境にローカル変数の値を設定できます。

以下はabc、期待どおりに出力されます (同じ効果でに変更できます) loadstringloadfile

function vars(f)
  local func = debug.getinfo(f, "f").func
  local i = 1
  local vars = {}
  while true do
    local name, value = debug.getlocal(f, i)
    if not name then break end
    if string.sub(name, 1, 1) ~= '(' then vars[name] = value end
    i = i + 1
  end
  i = 1
  while func do -- check for func as it may be nil for tail calls
    local name, value = debug.getupvalue(func, i)
    if not name then break end
    vars[name] = value
    i = i + 1
  end
  return vars
end

function parent()
  local var = "abc"

  local child = loadstring("print(var)")

  local env = vars(2) -- grab all local/upvalues for the current function
  -- use these values to populate new environment; map to _G for everything else
  setmetatable(env, {__index = _G})
  setfenv(child, env)

  child()
end

parent()

これはすべてLua 5.1の場合ですが、Lua 5.2でも可能です。

于 2013-05-23T23:22:51.800 に答える