2010-05-03 12 views
5
código

muestra:programación en Lua, objetos

function Account:new (o) 
    o = o or {} -- create object if user does not provide one 
    setmetatable(o, self) 
    self.__index = self 
    return o 
end 

tomado de:

http://www.lua.org/pil/16.1.html

¿Cuál es el propósito de la:

self.__index = self 

línea? ¿Y por qué se ejecuta cada vez que se crea un objeto?

Respuesta

5

Como han dicho otros, self (la tabla Account) se utiliza como metatabla asignado a los objetos creados con new. Simplificando ligeramente (más información disponible en los enlaces provistos) cuando un campo no se encuentra en 'o', va a la tabla 'Cuenta' porque el metatable de o dice que vaya a Cuenta (esto es lo que __index hace).

No es necesario, sin embargo, que se ejecute cada vez que se crea un objeto. Usted podría simplemente pegar esto en alguna parte:

Account.__index = Account 

y funcionaría también.

La historia algo más largo es que si un objeto o tiene un metatabla, y que metatabla tiene el conjunto __index campo, a continuación, un fallidos campo de búsqueda de o utilizará __index para encontrar el campo (__index puede ser una tabla o función). Si o tiene el campo configurado, no va a la función __index de su metatabla para obtener la información. De nuevo, sin embargo, te animo a leer más en los enlaces provistos arriba.

0

Se utilizan para redirigir los accesos a la tabla (local y = tabla [clave]) que también se utilizan en las llamadas a métodos. En la línea anterior, el objeto o tendrá cualquier intento de acceder a las claves redirigidas al objeto actual, heredando sin esfuerzo todas las funciones de los miembros. Y posiblemente también variables de datos, dependiendo de qué es exactamente ese __index y cómo funciona.

3

Lua no es un lenguaje orientado a objetos, pero tiene todas las facilidades para escribir código orientado a objetos. Sin embargo, se realiza de una manera prototyping a la JavaScript. En lugar de crear clases explícitamente, se crea un objeto prototipo y luego se clona para crear nuevas instancias.

Se invoca el meta-método __index para realizar búsquedas de teclas en accesos de lectura a una tabla cuando la clave no está presente en la tabla. Por lo tanto, self.__index = self esencialmente permite heredar todos los métodos y campos de la "clase" Account por la nueva "instancia" que se crea en las líneas o = o or {} y setmetatable(o, self).

Consulte también:

+0

Encontré este "tutorial" en Lua [inheritance] (http: // lua-users.org/wiki/InheritanceTutorial) particularmente esclarecedor junto con esta respuesta. – Indolering

+0

@Indolering Gracias. Puse tu enlace en la respuesta. –

4

La documentación Lua es un tanto vaga en este detalle y muchas de las respuestas aquí tampoco echo los documentos Lua o no explican los completamente este dato confuso.

La línea self._index = self está presente exclusivamente para el beneficio del objeto recién creado, o; no tiene un impacto significativo o funcional en Account.

El campo _index solo tiene un significado especial en el contexto de metatables; por lo tanto, self._index es simplemente un campo normal antiguo normal para Account. Sin embargo, cuando se usa Account como metatable para o, el campo _index "se convierte" en un meta-método para o. (Entonces, ¿qué es un campo para Account es un metamétodo para o.)

Cuando se toman las dos declaraciones en combinación ...

 
(1) setmetatable(o, self) 
(2) self._index = self 

... Estás usando Account como el metatabla o en línea (1) y estableciendo el meta-método _index para o en Account en la línea (2). (En la línea (2), que está también estableciendo el "campo viejo y simple" __index en Account a Account.) De modo que el aspecto útil de self._index = self no es la configuración del campo _index para Account, sino más bien la configuración de la _index metametodo para o.

El siguiente es funcionalmente equivalente:

 
    setmetatable(o, self) 
    getmetatable(o)._index = self 
+0

Tenga en cuenta que, si __index es un nombre metamódico en nombre, lua proporciona un acceso directo útil donde __index se le puede asignar una tabla en lugar de una función. En estos casos, cuando se llama __index, se realiza una búsqueda. Por lo tanto, cuando dices __index = self lo que realmente estás diciendo es que, si no puedes encontrar un campo determinado en la instancia de Cuenta, mira (también conocido como "índice") en la clase/prototipo de la Cuenta. – Aaron

0

Creación de objetos (que son simplemente las Tablas) es bastante diferente con Lua. La idea básica es crear una tabla regular que contenga atributos (funciones y valores) que sean comunes a todas las instancias. En esta tabla, llamaré CAT para la tabla de atributos comunes.

Si hace referencia a un atributo en una mesa y Lua no puede encontrar este atributo, hay una manera de contar Lua otro lugar para buscar el atributo. Queremos que Lua busque en el CAT los atributos comunes. Los metatablas responden a esa necesidad. Más sobre cómo funciona eso más tarde.

También necesitamos métodos en el CAT para poder usar valores de instancia. Self responde que necesita. Cuando llama a una función de tabla (método) de esta manera: tableName:methodName(), Lua automáticamente coloca una referencia al objeto de tabla como el primer parámetro. El nombre de este parámetro es self. Aunque el método se encuentra en el CAT, self se referirá a la tabla de instancia de objeto de llamada particular.

Digamos que tenemos un CAT llamado Car.

metaCar = { __index = Car } 
-- this table will be used as the metatable for all instances of Car 
-- Lua will look in Car for attributes it can't find in the instance 

Por ejemplo:

-- instance table is called mustang  
-- setmetatable(mustang, metaCar) 

Aquí es una función de propósito general que crea nuevos objetos instancia y establece el metatabla por ello. Si el CAT tiene una función de constructor (init), se ejecuta también.

function newObj(metatable) 
..obj = {}  -- create new empty instance object 
..setmetatable(obj, metatable) –- connect the metatable to it 
..if obj.init then -- if the CAT has an init method, execute it 
....obj:init() 
..end 
..return obj 
end