2011-10-25 11 views
5

Przepraszam, jeśli to zbyt oczywiste, ale jestem zupełnie nowym użytkownikiem lua i nie mogę go znaleźć w odnośniku.W Lua, czy istnieje funkcja, która dała funkcję, zwraca swoją nazwę jako ciąg znaków?

Czy istnieje funkcja NAME_OF_FUNCTION w Lua, która, biorąc pod uwagę funkcję, podaje mi swoją nazwę, dzięki czemu mogę indeksować z nią tabelę? Powód chcę to, że chcę zrobić coś takiego:

local M = {} 

local function export(...) 
    for x in ... 
    M[NAME_OF_FUNCTION(x)] = x 
    end 
end 

local function fun1(...) 
... 
end 

local function fun2(...) 
... 
end 

. 
. 
. 

export(fun1, fun2, ...) 

return M 
+0

Mogę po prostu przekazać ciąg, aby wyeksportować siebie, ale pomyślałem, że zapytam, ponieważ myślę, że jest bardziej elegancki, przechodząc przez samą funkcję. Chociaż jest to zbyt trudne, ponieważ nazwa jak w źródle żyje tylko w źródle. – Paralife

+1

Myślę, że mylisz się w tym miejscu "nazwa jak w źródle żyje tylko w źródle". Dotyczy to większości języków statycznych i kompilowanych, ale języki dynamiczne/języki skryptowe wywołują funkcje, wyszukując ich nazwy, dzięki czemu mogą mieć późniejsze wiązanie (i pozwalają na ponowne wiązanie funkcji z małpiącym kodem poprawki, itd.). – fortran

+1

możliwy duplikat [ Stringify nazwa obiektu w Lua] (http://stackoverflow.com/questions/6800648/stringify-object-name-in-lua) – finnw

Odpowiedz

5

Po prostu nie ma takiej funkcji. Chyba nie ma takiej funkcji, ponieważ funkcje są obywatelami pierwszej klasy. Tak więc funkcja jest po prostu wartością jak każda inna, do której odwołuje się zmienna. Stąd funkcja NAME_OF_FUNCTION nie byłaby bardzo przydatna, ponieważ ta sama funkcja może mieć wiele zmiennych wskazujących na to, lub żadna.

Można emulować jedną dla funkcji globalnych lub funkcji w tabeli, przechodząc przez tabelę (arbitralne lub _G), sprawdzając, czy wartość jest równa x. Jeśli tak, to znalazłeś nazwę funkcji.

a=function() print"fun a" end 
b=function() print"fun b" end 
t={ 
    a=a, 
    c=b 
} 
function NameOfFunctionIn(fun,t) --returns the name of a function pointed to by fun in table t 
    for k,v in pairs(t) do 
     if v==fun then return k end 
    end 
end 
print(NameOfFunctionIn(a,t)) -- prints a, in t 
print(NameOfFunctionIn(b,t)) -- prints c 
print(NameOfFunctionIn(b,_G)) -- prints b, because b in the global table is b. Kind of a NOOP here really. 

Innym rozwiązaniem byłoby zawinąć funkcji w tabeli i mają metatable założyć, że wywołuje funkcję, na przykład:

fun1={ 
    fun=function(self,...) 
     print("Hello from "..self.name) 
     print("Arguments received:") 
     for k,v in pairs{...} do print(k,v) end 
    end, 
    name="fun1" 
} 
fun_mt={ 
    __call=function(t,...) 
     t.fun(t,...) 
    end, 
    __tostring=function(t) 
     return t.name 
    end 
} 
setmetatable(fun1,fun_mt) 
fun1('foo') 
print(fun1) -- or print(tostring(fun1)) 

To będzie nieco wolniejsze niż przy użyciu gołych funkcje ponieważ z metatable wyszukiwania. Nie uniemożliwi to nikomu zmiany nazwy funkcji w stanie, zmiany nazwy funkcji w tabeli zawierającej ją, zmiany funkcji itp., Więc nie jest to zabezpieczeniem przed manipulacją. Można również usunąć tabele po indeksowaniu, takie jak fun1.fun, które mogą być dobre, jeśli wyeksportujesz je jako moduł, ale tracisz nazewnictwo i inne sztuczki, które możesz umieścić w metatable.

+0

Prawda o funkcji będącej wartością, ale to nie znaczy, że nie może być wartością złożoną, posiadającą kod funkcji i nazwę jako powiązane z nią metadane. Rozumiem, że jest to po prostu sposób Lua: każda zdefiniowana funkcja jest po prostu lambdą zapisaną w tabeli z kluczem, który nazywa się definicją funkcji: "Instrukcja funkcja f() koniec ciała tłumaczy się na f = funkcja() body end ", zgodnie z Lua reference – Paralife

+2

true, ale ten klucz nie musi być ciągiem znaków. Oto co jest poprawne w Lua: 't = {[function() print'foo 'end] = function() print'bar'end, {} = function() print'baz'end}' A więc tutaj są klucze odpowiednio funkcje i tabele. Mimo to tabela zawiera funkcje, a nie odwrotnie. Możesz dołączyć metadane do funkcji, ale zawsze będzie ona "zewnętrzna", tak jak w przykładach, które dałem. "W Lua funkcja nie jest wartością złożoną, jest tylko funkcją, zgodnie z filozofią Lua dotyczącą przekazywania narzędzi, które pozwalają budowanie czegokolwiek co to jest – jpjacobs

+0

prawda, i nie mam nic więcej do dodania :) – Paralife

0

Spróbuj tego:

http://pgl.yoyo.org/luai/i/tostring

toString (x) powinno być nadzieją co szukasz

+1

Byłem sceptyczny, że to działa, więc spróbowałem, i wygląda na to, że tak nie jest: http://codepad.org/uaZ2zSXW – delnan

+0

Och, wprawdzie zakładam trochę .. :( – Hybrid

+0

string.format również nie działa.Nie wydaje się być żadnej odpowiedniej opcji formatu ... – Paralife

0

If Nie jestem w błędzie (i prawdopodobnie, ponieważ właściwie nigdy nie programowałem w Lua, po prostu przeczytałem garść artykułów i artykułów), wewnętrznie istnieje już tabela z nazwami funkcji (jak locals i globals w Pythonie), więc powinieneś być w stanie wykonać odwrotne wyszukiwanie, aby zobaczyć, który klucz pasuje do odwołania do funkcji.

W każdym razie, tylko spekulacje.

Ale faktem jest, że patrząc na swój kod, już znasz nazwę funkcji, więc możesz swobodnie budować tabelę. Jeśli chcesz być mniej podatny na błędy, łatwiej byłoby użyć nazwy funkcji, aby uzyskać odwołanie do funkcji (z eval lub coś podobnego) niż na odwrót.

+0

Masz rację, ale po wkopaniu się w niego, najbliższą rzeczą, na jaką mógłbym się zdobyć, jest funkcja debug.getinfo, ale nie zwraca ona nazwy. tabela globalna nie wspomina o funkcjach lokalnych, wciąż szukam sposobu introspekcji, aby uzyskać nazwę od obiektu lub, jak powiedziałeś, odwrotnie: obiekt od nazwy, ale bez powodzenia do tej pory – Paralife

+1

Wartość funkcji może mieć wiele nazw lub nie ma ich wcale. – lhf

1

Technicznie jest to możliwe, oto implementacja eksport() Funkcja:

function export(...) 
     local env = getfenv(2); 
     local funcs = {...}; 
     for i=1, select("#", ...) do 
       local func = funcs[i]; 
       for local_index = 1, math.huge do 
         local local_name, local_value = debug.getlocal(2, local_index); 
         if not local_name then 
           break; 
         end 
         if local_value == func then 
           env[local_name] = local_value; 
           break; 
         end 
       end 
     end 
     return env; 
end 

Używa debug API, będzie wymagać pewnych zmian w Lua 5.2, a na końcu ja nie koniecznie poprzeć go jako dobry sposób pisania modułów, po prostu odpowiadam na to pytanie dosłownie.

Powiązane problemy