2

以下の行を含む「test.lua」というファイル名があるとします。

--[[  test.lua --]]
local f = function()
  print"local function f in test.lua"
end

f_generate = function()
  local fun = loadstring(" f()")
-- local env = getfenv(1)
-- set(fun,env)
  return fun
end
f_generate()()
--[[ end of test.lua--]]

loadstring はグローバル環境で処理を行っているため、f_generate()() を呼び出すと、「グローバル 'f' (nil 値) を呼び出そうとしています」というエラーが表示されます。

コメントアウトされたコードは、関数環境がこの問題に対処できないことを示しています。

原因テーブルは lua の唯一のデータ構造です (そして、関数環境と他の多くのものはテーブルによって実装されます)、クロージャーもテーブルによって実装されると仮定するのは合理的だと思いますが、どうすれば取得できますか?

4

4 に答える 4

4

loadstring()尋ねられた質問と提供されたサンプルコードから、関数とクロージャーが言語のファーストクラスの値であるときに使用する必要はないと思います。私は次のようにすることを検討します:

-- test.lua
ローカル f = 関数()
  print"test.lua のローカル関数 f"
終わり

f_generate = 関数()
  local fun = function() return f() end
  楽しみを返す
終わり
f_generate()()
-- test.lua の終了

f_generate へのパラメーターがある場合、動機はより明確になります。

-- test.lua
ローカル f = 関数 (y)
  print("ローカル関数 f("..y..") in test.lua")
終わり

f_generate = 関数 (名前)
  local fun = function() return f(名前) end
  楽しみを返す
終わり
f_generate("foo")()
f_generate("バー")()
-- test.lua の終了

でパーサーを通過するとloadstring()、コードが への呼び出しの範囲外に明示的に取り込まれloadstring()ます。ローカル変数は、どの環境テーブルにも保存されません。これらは、他の言語とほぼ同じ方法で実装されます。それらのストレージは、コード ジェネレーターによって割り当てられ、そのコンパイルの外ではアクセスできません。もちろん、デバッグ モジュール (および API) にはそれらを覗く機能がありますが、デバッガー以外で使用することはお勧めできません。

スコープ外で使用するためにローカルへの参照を保持する正しい方法は、クロージャーの真の上位値として使用することです。それがによって達成されるものですfun = function() return f() end。その場合、値fは に格納されている関数の上位値として保持されfunます。実際には、この上位値としてのラップは非常に効率的であることに注意してください。値を見つけるために名前を検索する必要はありません。末尾呼び出しを使用したため、追加のスタック フレームも必要ありません。

于 2009-05-22T20:56:05.220 に答える
0

私はあなたが2つの異なるものを混ぜていると思います:

  1. クロージャ:このため、f()の定義は、囲みたいローカル変数のスコープ内にある必要があります。

    • 動的にコンパイルされた関数にローカル変数を挿入します。これはLuaによって正式にサポートされていません。それは環境問題ではなく、スコープの問題です。

覚えておいてください:スコープは字句ですが、環境は各関数が「グローバルスペース」と見なすものです。

テキスト文字列から構築された関数は、別のファイルにあるかのように別の字句空間にあるため、他の関数から分離された独自のスコープを持っています。

ところで、「デバッグ」インターフェースを使用すると、関数のローカル変数を操作できるので、方法があるかもしれません。私はこれをする必要性を感じていません。

于 2009-05-22T14:03:12.440 に答える
0

「ローカル」を削除する必要があります。そうしないと、ガベージ コレクションが行われます。

--local f = function()
f = function()
  print"local function f in test.lua"
end
于 2009-05-22T14:10:48.697 に答える
0

関数/クロージャーをテーブルとして扱うことはできません。次のコードを検討してください。

local table = {
    baz = {
        blah = "bar"
    },
    foo = table.baz.blah
}

この場合、より広いスコープからより狭いスコープで何かにアクセスするのと同じことを実行しています。これは関数では不可能です。つまり、これが当てはまる場合、通常はアクセスできないローカル変数にアクセスできます。

次に、コードを修正します。

local __cmp__table = { 
    [">"] = function(a,b) return a>b end, 
    [">="] = function(a,b) return a>=b end, 
    ["<"] = function(a,b) return a<b end, 
    ["<="] = function(a,b) return a<=b end, 
    ["=="] = function(a,b) return a==b end, 
    ["~="] = function(a,b) return a~=b end, 
} 
cmp = function(a, op, b) 
    return __cmp__table[op](a,b) 
end

これにより、適切な比較関数を使用して、任意の 2 つの変数に対して cmp を呼び出すことができます。あなたのコードについてのポイントを逃した場合は、教えてください!

于 2009-08-24T02:58:36.347 に答える