En este módulo, exploraremos uno de los conceptos más poderosos y flexibles de Lua: las metatablas y los metamétodos. Estos permiten modificar el comportamiento de las tablas, proporcionando una forma de implementar características avanzadas como la sobrecarga de operadores y la herencia.

¿Qué es una Metatabla?

Una metatabla es una tabla especial que puede cambiar el comportamiento de otra tabla. Puedes pensar en una metatabla como una "tabla de configuración" que define cómo se comporta la tabla a la que está asociada.

Creación de una Metatabla

Para crear una metatabla, simplemente defines una tabla normal y luego la asocias a otra tabla usando la función setmetatable.

local myTable = {}
local myMetatable = {}

setmetatable(myTable, myMetatable)

Acceso a la Metatabla

Puedes acceder a la metatabla de una tabla usando la función getmetatable.

local mt = getmetatable(myTable)
print(mt == myMetatable)  -- true

Metamétodos

Los metamétodos son funciones que puedes definir en una metatabla para cambiar el comportamiento de las operaciones en la tabla asociada. Aquí hay algunos de los metamétodos más comunes:

__index

El metamétodo __index se utiliza para cambiar el comportamiento de la indexación de una tabla. Si intentas acceder a una clave que no existe en la tabla, Lua buscará en la metatabla bajo la clave __index.

local myTable = {}
local myMetatable = {
    __index = function(table, key)
        return "Key not found"
    end
}

setmetatable(myTable, myMetatable)

print(myTable.someKey)  -- "Key not found"

__newindex

El metamétodo __newindex se utiliza para cambiar el comportamiento de la asignación de valores a claves que no existen en la tabla.

local myTable = {}
local myMetatable = {
    __newindex = function(table, key, value)
        print("Attempt to set " .. key .. " to " .. value)
    end
}

setmetatable(myTable, myMetatable)

myTable.someKey = "someValue"  -- "Attempt to set someKey to someValue"

__add

El metamétodo __add se utiliza para cambiar el comportamiento del operador de suma (+).

local myTable1 = {value = 10}
local myTable2 = {value = 20}
local myMetatable = {
    __add = function(table1, table2)
        return table1.value + table2.value
    end
}

setmetatable(myTable1, myMetatable)
setmetatable(myTable2, myMetatable)

local result = myTable1 + myTable2
print(result)  -- 30

Otros Metamétodos

Aquí hay una tabla con algunos otros metamétodos comunes:

Metamétodo Descripción
__sub Resta (-)
__mul Multiplicación (*)
__div División (/)
__mod Módulo (%)
__pow Potencia (^)
__concat Concatenación (..)
__eq Igualdad (==)
__lt Menor que (<)
__le Menor o igual que (<=)

Ejemplo Práctico

Vamos a crear un ejemplo práctico que utilice varios metamétodos para definir un comportamiento personalizado para una tabla que representa un vector 2D.

local Vector2D = {}
Vector2D.__index = Vector2D

function Vector2D:new(x, y)
    local vec = {x = x, y = y}
    setmetatable(vec, self)
    return vec
end

function Vector2D:__add(other)
    return Vector2D:new(self.x + other.x, self.y + other.y)
end

function Vector2D:__tostring()
    return "(" .. self.x .. ", " .. self.y .. ")"
end

local vec1 = Vector2D:new(1, 2)
local vec2 = Vector2D:new(3, 4)
local vec3 = vec1 + vec2

print(vec3)  -- (4, 6)

Ejercicios Prácticos

Ejercicio 1: Implementar __sub

Implementa el metamétodo __sub para la clase Vector2D que permita restar dos vectores.

function Vector2D:__sub(other)
    return Vector2D:new(self.x - other.x, self.y - other.y)
end

local vec4 = vec1 - vec2
print(vec4)  -- (-2, -2)

Ejercicio 2: Implementar __eq

Implementa el metamétodo __eq para la clase Vector2D que permita comparar dos vectores por igualdad.

function Vector2D:__eq(other)
    return self.x == other.x and self.y == other.y
end

local vec5 = Vector2D:new(1, 2)
print(vec1 == vec5)  -- true

Conclusión

En esta sección, hemos aprendido sobre metatablas y metamétodos en Lua, y cómo pueden ser utilizados para modificar el comportamiento de las tablas. Estos conceptos son fundamentales para aprovechar al máximo la flexibilidad y el poder de Lua. En el próximo módulo, exploraremos cómo utilizar módulos y paquetes para organizar y reutilizar el código de manera eficiente.

© Copyright 2024. Todos los derechos reservados