2012-03-08 22 views
5

Estoy tratando de entender qué hace esta función. ¿Puede alguien explicarme esto?Tratando de entender este fragmento de lua

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

Se llama así:

self = newInstance (self) 
+0

Por favor, que alguien dé un mejor título a esta pregunta porque yo creo que va a ayudar a algunos desarrolladores por ahí. – chchrist

Respuesta

6

Esta función sirve para proporcionar al parecer, una variante de programación orientada a objetos en Lua (un poco descuidado en mi opinión).

Esta es una fábrica para una clase.

Puede ser reescrita como sigue, para mayor claridad:

C = { } 

C.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C.__index = C -- (A) 

function newInstance(class) 
    return setmetatable({ }, class) -- (B) 
end 

Ahora si creamos dos nuevas instancias de C, vemos claramente que ambos tienen un foo método(), pero diferente de auto:

o1 = newInstance(C) 
o1:foo() --> foo method called table: 0x7fb3ea408ce0 

o2 = newInstance(C) 
o2:foo() --> foo method called table: 0x7fb3ea4072f0 

los métodos foo son los mismos:

print(o1.foo, o2.foo, o1.foo == o2.foo and "equal" or "different") 
--> function: 0x7fb3ea410760 function: 0x7fb3ea410760 equal 

Esto es porque la tabla C (la "clase") es un __index ((A) arriba) de metatable de o1 y o2, establecido en (B). Pero o1 y o2 son en realidad dos tablas diferentes, creadas en (B) (las "instancias de clase" u "objetos").

Nota: establecemos que C.__index sea igual a C en sí en (A) por lo que reutilizaríamos una tabla. A continuación tiene el mismo efecto:

prototype = { } 

prototype.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C = { __index = prototype } 

function newInstance(class) 
    return setmetatable({ }, class) 
end 

o = newInstance(C) 
1

Esto se utiliza para lograr el comportamiento orientado a objetos en Lua. Lua usa herencia basada en prototipos (similar a Javascript) en lugar de herencia basada en clases (como Java o C++). La idea es que todos los métodos de clase se implementen como parte de un objeto prototipo y hereden objetos delegados al prototipo al momento de la llamada.

Por ejemplo, suponga que desea que una clase myClass proporcionar un método getMagicNumber:

local myClass = { 
    getMagicNumber = function(self) 
     return self.theNumber; 
    end }; 

local obj = newInstance(myClass); 
obj.theNumber = 42; 
print(obj:getMagicNumber()); -- supposed to return 42 

Es una especie de un ejemplo trivial, pero espero que se entiende la idea. Lo que sucede es esto: newInstance crea una nueva tabla con su metatabla apuntando a myClass y también asegura que el campo __index del metatabla también apunta a myClass. Como describe el manual de Lua en __index, cuando intenta llamar a getMagicNumber en esa nueva tabla, sucede lo siguiente: Primero Lua intenta encontrar el campo getMagicNumber en la tabla obj. Sin embargo, dado que la tabla está vacía, ahora busca en su campo __index (myClass). Como el campo se encuentra allí, ahora llama a la función que se encuentra en myClass.

Programming in Lua analiza este mecanismo en gran detalle si necesita saber más.

1

No estás solo, me tomó un poco de tiempo asimilar este código.Aquí está mi interpretación

cada tabla puede tener un netatable, el metatable puede almacenar, entre otras cosas, funciones indexadas por nombre, y setmetatable establece el valor de la metatabla con la suficiente naturalidad.

La línea class._index = .. es donde ocurre la magia.

Cuando intenta llamar a una función usando self.fn1(), Entonces lua busca en sí un nombre fn1. Si no puede encontrarlo, busca en el metatabla de uno mismo una tabla __index, y busca un 'fn1' en la tabla almacenada allí.

Ahora la metatabla de self en su ejemplo es class, por lo que lua busca una __index entry en la metatabla (clase) para ver si hay una función llamada fn1 en esa tabla, y la hay, por lo que se devuelve. Necesitas establecer el __index para la clase a sí mismo para que lua se vea en el mismo metatable - confuso hey.

(como una asignación de __index solo tiene que suceder una vez, pero por alguna razón siempre se hace en el nuevo operador en todos los ejemplos de lua - lo tomo fuera de lo nuevo en mis clases - guarda unos ciclos)

A continuación, devuelve la nueva tabla o, lua es basura recolectada, por lo que devolver un local crea una nueva tabla cada vez.

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

hth

Cuestiones relacionadas