2013-05-11 19 views
6

mam problemy ze zrozumieniem, dlaczego istnieje różnica w zachowaniu się __index metamethod między tych przykładów:Lua Metatable Niespójność

A = { __index = A } 
function A:speak() 
    print("I'm an A") 
end 
An_A = setmetatable({},A) 
An_A:speak() 

podniesie się następujący błąd: lua: l.lua:8: attempt to call method 'speak' (a nil value)

podczas

B = { __index = function(t,key) return B[key] end } 
function B:speak() 
    print("I'm an B") 
end 
An_B = setmetatable({},B) 
An_B:speak() 

Wykona się zgodnie z oczekiwaniami, wyprowadzając I'm an B.


Próbując zrozumieć, dlaczego miało to czytam this odcinek pil. Stwierdza ona, że:

The use of the __index metamethod for inheritance is so common that Lua provides a shortcut. Despite the name, the __index metamethod does not need to be a function: It can be a table, instead. When it is a function, Lua calls it with the table and the absent key as its arguments. When it is a table, Lua redoes the access in that table.

Moje zrozumienie tego jest, że we fragmencie z udziałem „a”, __index = A powodować dostępu do zrobienia w tabeli A (zgodnie z boldened segmenet wyżej cytat). W takim przypadku nie rozumiem, dlaczego funkcja związana z kluczem "speak" nie została znaleziona. Próbując to naprawić, postanowiłem zaimplementować podejście funkcji w kodzie B, które zwraca wartość związaną z key w B i zadziałało. Z pewnością __index = A i (dostosowany od B) __index = function(t,key) return A[key] end mają taki sam efekt.

Wszelkie wyjaśnienia byłyby bardzo mile widziane.

Odpowiedz

9

To, co dzieje się w pierwszym przykładzie, to A.__index == nil. Podczas tworzenia „A” na pierwszej linii tutaj:

A = { __index = A } 

Bok prawy z cesją „A” ocenia się nil ponieważ nie istnieje jeszcze w tym momencie. W rezultacie, później po ustawieniu metatable tutaj:

An_A = setmetatable({},A) 

tak naprawdę kończy się robi coś podobnego do tego:

An_A = setmetatable({}, {__index = nil}) 

Aby zmusić go do pracy tak, jak chcesz, masz do upewnij się, że __index nie jest nil. Na przykład przypisz go po zbudowaniu tabeli:

A = {} 
A.__index = A 

function A:speak() 
    print("I'm an A") 
end 
An_A = setmetatable({},A) 
An_A:speak()    --> outputs I'm an A 
+0

Dziękuję za wielkie wyjaśnienie, nie przyszło mi do głowy, że to się stanie, założyłem, że będzie to jak inne języki, w których coś takiego jak 'f = lambda n: f (n) 'jest poprawna. Pozdrawiam :) – HennyH

+1

@HennyH: 'f = function (n) return f (n) end' jest w porządku w lua z tego samego powodu. Odpowiednikiem pytającego błędu jest 'd = {" __indeks ": d}', ale python będzie "NameError' – Eric

+0

@Eric Przypuszczam, że każda funkcja rekurencyjna podąża za tym samym wzorcem. – HennyH