Vinculación con __index
Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 7 de 70.
Tienes una tabla prototipo con propiedades y métodos, ¿pero cómo haces que un nuevo objeto realmente la use? La respuesta reside en el metamétodo __index.
Cuando accedes a una clave que no existe en una tabla, Lua normalmente devuelve nil. Sin embargo, si la tabla tiene una metatabla con un campo __index, Lua buscará allí en su lugar. Al configurar __index para que apunte a tu prototipo, cualquier clave que falte se encontrará automáticamente en el prototipo:
local Dog = {
species = "Canis familiaris",
legs = 4
}
function Dog:bark()
print("Woof!")
end
-- Crear una instancia vacía
local myDog = {}
-- Enlazarlo al prototipo
setmetatable(myDog, { __index = Dog })
print(myDog.species) -- Salida: Canis familiaris
myDog:bark() -- Salida: Woof!La tabla myDog está completamente vacía, sin embargo, acceder a myDog.species funciona. Cuando Lua no encuentra species en myDog, consulta el __index de la metatabla y lo encuentra en Dog.
Esta es la base de la programación orientada a objetos en Lua. La instancia puede tener sus propios datos únicos, mientras que el comportamiento compartido reside en el prototipo. En la siguiente lección, aprenderás cómo envolver este patrón en una función constructora limpia.
Desafío
Fácil¡Ahora pongamos en práctica el metamétodo __index! Crearás un prototipo y vincularás una instancia a él, permitiendo que la instancia acceda a propiedades y métodos que no posee directamente.
Organizarás tu código en dos archivos:
Robot.lua: Define una tabla prototipoRobotcon:- Un campo
modelestablecido en"RX-100" - Un campo
batteryLevelestablecido en100 - Un método
:status()que imprima el estado actual del robot
- Un campo
main.lua: Requiere el módulo Robot, luego crea una tabla de instancia vacía y vincúlala al prototipo Robot usandosetmetatablecon__index. Esto permite que tu instancia vacía acceda a todo lo del prototipo.
Recibirás una entrada: un nombre para asignar a tu instancia de robot.
Después de vincular la instancia al prototipo:
- Asigna el nombre de entrada al campo
namede tu instancia (esto se vuelve único para la instancia) - Llama al método
:status()en tu instancia
Tu método :status() debe imprimir en este formato exacto:
[name] ([model]) - Battery: [batteryLevel]%Por ejemplo, si la entrada es Sparky, la salida debería ser:
Sparky (RX-100) - Battery: 100%Observa cómo la instancia tiene su propio name, pero accede a model y batteryLevel desde el prototipo a través del enlace __index.
Hoja de referencia
El metamétodo __index permite que los objetos hereden propiedades y métodos de una tabla prototipo.
Cuando accedes a una clave que no existe en una tabla, Lua comprueba si la tabla tiene una metatabla con un campo __index. Si es así, Lua busca la clave en la tabla especificada por __index.
Para vincular una instancia a un prototipo:
local Prototype = {
property = "value"
}
function Prototype:method()
print("Method called")
end
-- Create an instance
local instance = {}
-- Link to prototype using __index
setmetatable(instance, { __index = Prototype })
-- Access prototype properties and methods
print(instance.property) -- Output: value
instance:method() -- Output: Method calledLa tabla de la instancia puede estar vacía y, aun así, puede acceder a todas las propiedades y métodos del prototipo. La instancia también puede tener sus propias propiedades únicas que anulan o extienden el prototipo.
Este patrón es la base de la programación orientada a objetos en Lua, donde las instancias comparten el comportamiento de un prototipo mientras mantienen sus propios datos únicos.
Pruébalo tú mismo
-- Leer entrada
local name = io.read()
-- Requerir el módulo Robot
local Robot = require('Robot')
-- TODO: Crear una tabla de instancia vacía
-- TODO: Vincular la instancia al prototipo Robot usando setmetatable con __index
-- TODO: Asignar el nombre de entrada al campo name de tu instancia
-- TODO: Llamar al método :status() en tu instancia
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1El concepto de 'self'
Tablas con funciones'self' explícitoLa sintaxis de dos puntosPunto vs. dos puntosResumen - Punto en movimiento4Proyecto: Banco Digital
Configuración del proyectoMétodo de depósito2Patrón de prototipo de clase
El concepto de prototipoVinculación con __indexEl constructor :new()Inicialización de atributosInstancias independientesResumen - Fábrica de coches5Sobrecarga de operadores en POO
Sumar objetosRestar objetosConcatenar objetosComparar objetos (<, >)Resumen - Matemáticas de la billetera8Encapsulamiento
Convenciones de nomenclaturaClosures para privacidadAcceso mediante ClosuresTablas de solo lecturaLógica de validaciónResumen - Bóveda segura11Patrones de diseño (Lite)
Funciones FactoryTabla SingletonPatrón IteradorObserver (Listener)Resumen - Logger Factory3Estado y Comportamiento de los Objetos
Variables de InstanciaMétodos GetterMétodos SetterPropiedades CalculadasFormateo de StringsComprobaciones de IgualdadResumen - Calificación del Estudiante6Fundamentos de la herencia
Configuración de la herenciaHerencia de métodosExtender el constructorAñadir métodos hijosCompartido vs. ÚnicoResumen: Jerarquía de formas