5

RobertoIerusalimschyの「ProgramminginLua」から学んでいます。この本では、サンドボックスの例で関数を使用しsetfenv()て特定の関数の環境を変更していることがわかりましたが、lua5.2ではこの関数は使用できなくなりました。

ファイル(構成ファイル)からテーブルのフィールドにいくつかの値をロードしようとしましたが、lua 5.2ではsetfenvを使用できません(特定の環境で値をロードできます)。lua 5.2に関するいくつかの記事を読んだ後、各関数が環境として機能する_ENVと呼ばれるアップバリューを持っている(または持っていない)可能性があることがわかったので、次のコードを試しました。

function sandbox(sb_func, sb_env)
    if not sb_func then return nil, "sandbox function not valid" end
    sb_orig_env = _ENV
    _ENV = sb_env -- yes, replaces the global _ENV
    pcall_res, message = pcall( sb_func )
    local modified_env = _ENV -- gets the environment that was used in the pcall( sb_func )
    _ENV = sb_orig_env
    return true, modified_env
end

function readFile(filename)
    code = loadfile(filename)
    res, table = sandbox(code, {})
    if res then
        --[[ Use table (modified_env) ]]--
    else
        print("Code not valid")
end

'sandbox'関数での置換_ENVはうまく機能します(通常のフィールドにアクセスできません)が、'コード'を実行すると、置換したことを無視しているように見え_ENVますが、通常のフィールド(print、loadfile、dofile、等)。

もう少し読んでみると、lua 5.2がこの目的のための関数を提供していることがわかりました。この関数はloadin(env, chunk)、指定された環境で指定されたチャンクを実行しますが、この関数をコードに追加しようとすると、関数が存在しません。 (グローバル_Gフィールドには存在しません)。

いくつかの助けをいただければ幸いです。

4

1 に答える 1

7

_ENV内からに割り当てる場合、グローバル環境を上書きsandboxするのではなく、現在実行中のコードのアップバリューを置き換えることになります。に呼び出しを追加すると、関連するテーブルのIDをよりよく理解するのに役立つ場合があります。_ENVprint(_ENV)

例えば:

function print_env()
  print(_ENV)
end

function sandbox()
  print(_ENV) -- prints: "table: 0x100100610"
  -- need to keep access to a few globals:
  _ENV = { print = print, print_env = print_env, debug = debug, load = load }
  print(_ENV) -- prints: "table: 0x100105140"
  print_env() -- prints: "table: 0x100105140"
  local code1 = load('print(_ENV)')
  code1()     -- prints: "table: 0x100100610"
  debug.setupvalue(code1, 1, _ENV) -- set our modified env
  code1()     -- prints: "table: 0x100105140"
  local code2 = load('print(_ENV)', nil, nil, _ENV) -- pass 'env' arg
  code2()     -- prints: "table: 0x100105140"
end

このloadin機能は、Lua 5.2の一部のプレリリースバージョンに存在していましたが、最終リリースの前に削除されました。代わりに、Lua5.2loadloadfile関数は引数を取りenvます。_ENVを使用して別の関数のを変更することもできますdebug.setupvalue

于 2012-07-01T08:40:13.853 に答える