グローバル環境を汚染せずにluaテーブルと変数のファイルをロードするにはどうすればよいですか?ロードファイルを実行して実行すると、グローバルスペースのすべてがロードされ、不要なものが上書きされる可能性があります。
3 に答える
Lua 5.1では、多くのエラー処理なしでこれを行うことができます:
-- load and run a script in the provided environment
-- returns the modified environment table
function run(scriptfile)
local env = setmetatable({}, {__index=_G})
assert(pcall(setfenv(assert(loadfile(scriptfile)), env)))
setmetatable(env, nil)
return env
end
最初の行は、既存のすべてのグローバルを表示できる空の環境テーブルを作成しますが、メタメソッドを介したプロキシによってのみ表示されるため、それらを簡単に変更することはできません__index
。スクリプトが作成するグローバルはすべて、に格納されenv
、返されます。これは、一連の構成パラメーターを設定するだけの単純なスクリプトでうまく機能し、実行時の条件に基づいてそれらを設定するために単純な安全な関数を呼び出す必要がある場合があります。
グローバルをスクリプトから見えるようにするのは便利であることに注意してください。グローバルはスクリプトから明白な方法で変更することはできませんが、グローバル環境( 、など_G
を含む)への参照を含むグローバル変数であり、スクリプトから変更できるため、さらに問題が発生する可能性があります。_G._G
_G._G._G
_G
したがって、インデックスに使用するよりも_G
、安全であり、スクリプトの作成者が必要としていることがわかっている関数のみを含むテーブルを作成する方がはるかに優れています。
完全な解決策は、サンドボックスでスクリプトを実行し、偶発的な(または意図的な)サービス拒否またはそれ以上の事態を防ぐためにさらに保護することです。サンドボックスについては、LuaユーザーのWikiで詳しく説明されています。トピックは一見したところよりも深いですが、ユーザーが悪意のないものであると信頼されている限り、実用的なソリューションは簡単です。
setfenv()
Lua 5.2は、への新しいパラメーターを優先して削除することにより、状況を少し変更しますload()
。詳細はwikiページにもあります。
これは、RBerteigの回答のdofile()バージョンであり、環境を提供すると、結果が返されます(コメントとしてこれを実行しようとしましたが、フォーマットすることができませんでした)。
local function DofileIntoEnv(filename, env)
setmetatable ( env, { __index = _G } )
local status, result = assert(pcall(setfenv(assert(loadfile(filename)), env)))
setmetatable(env, nil)
return result
end
同じ環境に複数のファイルをロードできるようにしたかったのですが、これらのファイルのいくつかには「何かを返す」が含まれていました。RBerteigに感謝します、あなたの答えは役に立ち、有益でした!
Lua> 5.2
function run_test_script(scriptfile)
local env = setmetatable({}, {__index=_G})
assert(pcall(loadfile(scriptfile,"run_test_script",env)))
setmetatable(env, nil)
return env
end