たとえば、私はテーブルを持っています
table.insert( t, 1, function()
print ("rock");
end );
このテーブルから関数名を取得する方法はありますか?名前をキーのように保存できることは知っていますが、数値インデックスを保持したい場合や関数名も知りたい場合はどうすればよいですか?それを行う方法はありますか?よろしくお願いします。
あなたがこのコードを持っているとしましょう:
t = {}
x = 5
table.insert(t, 1, x)
t
その後、になります{[1] = 5}
。「5」は単なる数字です。名前はなく、変数「x」には関連付けられていません。それは値です。Luaでは、関数は値
とまったく同じように扱われます。
t = {}
x = function() print("test! :D") end
table.insert(t, 1, x)
xの値は、いかなる方法、形状、または形式でもxに関連付けられていません。関数に手動で名前を付ける場合は、次のように関数をテーブルにラップすることで名前を付けることができます。
t = {}
x = function() print("test! :D") end
table.insert(t, 1, {
name = "MyFunctionName",
func = x
})
それはあなたがそれをする方法です!
.....でない限り
..あなたはルールを破ります!
Luaが開発されたとき、開発者は、関数の匿名性により、不可能ではないにしても、生産的なエラーメッセージを生成するのが困難になることに気づきました。
あなたが見るであろう最高のものは次のようになります:
stdin: some error!
stdin: in function 'unknown'
stdin: in function 'unknown'
そこで彼らは、Luaコードが解析されたときに、デバッグ情報を記録して、作業を楽にするようにしました。Lua自体からこの情報にアクセスするために、デバッグライブラリが提供されています。
このライブラリの関数には十分注意してください。
このライブラリを使用するときは注意が必要です。ここで提供される関数は、デバッグおよびプロファイリングなどの同様のタスクにのみ使用する必要があります。それらを通常のプログラミングツールとして使用したいという誘惑に抵抗してください。非常に遅くなる可能性があります。さらに、これらの関数のいくつかは、Luaコードに関するいくつかの仮定に違反しているため(たとえば、関数のローカル変数に外部からアクセスできない、またはユーザーデータメタテーブルをLuaコードで変更できない)、それ以外の場合は安全なコードを危険にさらす可能性があります。
目的の効果を得るには、debug.getinfo
関数を使用する必要があります。例:
x = function()
print("test!")
print(debug.getinfo(1, "n").name)
end
x() -- prints "test!" followed by "x"
残念ながら、関数を直接操作するdebug.getinfoの形式では、name
引数(debug.getinfo(x, "n").name == nil
)が満たされません。上記のバージョンでは、関数を実行する必要があります。
絶望的なようです!
.....でない限り
..あなたは本当にルールを破ります。
このdebug.sethook
関数を使用すると、特定のイベントでLuaコードの実行を中断したり、すべてが発生している間に変更したりすることができます。これをコルーチンと組み合わせると、興味深いことにハッキーなことを行うことができます。
これがの実装ですdebug.getfuncname
:
function debug.getfuncname(f)
--[[If name found, returns
name source line
If name not found, returns
nil source line
If error, returns
nil nil error
]]
if type(f) == "function" then
local info = debug.getinfo(f, "S")
if not info or not info.what then
return nil, nil, "Invalid function"
elseif info.what == "C" then
-- cannot be called on C functions, as they would execute!
return nil, nil, "C function"
end
--[[Deep magic, look away!]]
local co = coroutine.create(f)
local name, source, linedefined
debug.sethook(co, function(event, line)
local info = debug.getinfo(2, "Sn")
name = info.namewhat ~= "" and info.name or nil
source, linedefined = info.short_src, info.linedefined
coroutine.yield() -- prevent function from executing code
end, "c")
coroutine.resume(co)
return name, source, linedefined
end
return nil, nil, "Not a function"
end
使用例:
function test()
print("If this prints, stuff went really wrong!")
end
print("Name = ", debug.getfuncname(test))
この関数はあまり信頼性が高くありません。機能する場合と機能しない場合があります。デバッグライブラリは非常に扱いにくいので、期待されています。
これを実際のリリースコードに使用しないでください。デバッグ専用です!
まだ受け入れられる最も極端なケースは、開発者が問題を修正するのを助けるために、リリースされたソフトウェアの一部にエラーを記録することです。重要なコードは、デバッグライブラリの関数に依存するべきではありません。
幸運を!
関数には名前がありません。必要に応じて、名前付き変数に割り当てることができます。
theFunction = t[1]
-- Call it:
theFunction()
名前付き関数をテーブルに格納する必要がある場合は、事前に定義し、その名前を使用して格納します。
theFunction = function()
print ("rock");
end
table.insert(t, 1, theFunction)
これが意図したものでない場合は、詳細を記入してください。たとえば、関数にどのようにアクセスしたいか。あなたの質問は少し霧がかかっています。
table.insertは、数値キーのみを使用して、テーブルをシーケンスと見なします。
関数を呼び出すことができるようにするt.fun()
場合は、テーブルを連想配列として使用する必要があるため、文字列をキーとして使用する必要があります。(ところで、nilまたはNaN以外のタイプはキーとして許可されます)
t={}
t['MyFun']=function print'foo' end
t.myFun() -- uses syntactic sugar for string keys that are valid identifiers.
また、関数が参照によって渡されることに気付くかもしれません。したがって、すべての関数は実際には匿名であり、特定のキーまたは変数の値として格納されるだけです。
名前は別のテーブルに保存できます。
functions = {}
functionNames = {}
function addFunction(f, name)
table.insert(functions, f)
functionNames[name] = f
end
関数を取得するには、インデックスを使用できます。関数を取得したら、function_namesからその名前を取得できます。
f = functions[3]
name = functionNames[f]
幸運を!