متا‌جدول‌ها (Metatables) در لوا

مفهوم متا‌جدول، setmetatable، متامتود __index و __newindex — پایه OOP در لوا

متا‌جدول چیست؟

متا‌جدول (Metatable) جدولی پشت‌صحنه است که رفتار جدول اصلی را تغییر می‌دهد — مثل DNA که مشخص می‌کند جدول در موقعیت‌های مختلف چه رفتاری داشته باشد.

متا‌جدول‌ها پایه همه چیز پیشرفته در لوایند: شی‌گرایی، وراثت، عملگرهای سفارشی و...

setmetatable و getmetatable

local t = {}

local mt = {}              -- متا‌جدول
setmetatable(t, mt)        -- اتصال

print(getmetatable(t) == mt)   -- true

__index — جستجوی کلید ناموجود

مهم‌ترین متامتود! وقتی کلیدی در جدول نباشد، لوا در __index دنبالش می‌گرد:

local defaults = {color = "مشکی", size = "متوسط"}

local obj = setmetatable({}, {__index = defaults})

print(obj.color)   -- مشکی! (از defaults آمد)
print(obj.size)    -- متوسط

-- مقدار مستقیم بر متا‌جدول اولویت دارد
obj.color = "قرمز"
print(obj.color)   -- قرمز (مقدار خودش)

__index می‌تواند تابع هم باشد

local t = setmetatable({}, {
__index = function(table, key)
return "کلید " .. key .. " وجود ندارد!"
end
})

print(t.foo)   -- کلید foo وجود ندارد!

__newindex — کنترل مقداردهی

وقتی کلید جدیدی مقداردهی می‌شود، صدا زده می‌شود:

local storage = {}
local proxy = setmetatable({}, {
__newindex = function(t, key, value)
print("درج: " .. key .. " = " .. tostring(value))
rawset(t, key, value)   -- درج واقعی
end,
__index = function(t, key)
return rawget(t, key)
end
})

proxy.name = "علی"   -- درج: name = علی
print(proxy.name)    -- علی

rawget و rawset — دور زدن متا‌جدول

local t = setmetatable({}, {
__index = function() return "پیش‌فرض" end
})

print(t.anything)      -- پیش‌فرض (از متا‌جدول)
print(rawget(t, "anything"))   -- nil (مستقیم، بدون متا‌جدول)

rawset(t, "real", 42)
print(rawget(t, "real"))   -- 42

جدول read-only با متا‌جدول

local function readOnly(t)
local proxy = {}
setmetatable(proxy, {
__index = t,
__newindex = function()
  error("این جدول فقط‌خواندنی است!", 2)
end
})
return proxy
end

local config = readOnly({host = "localhost", port = 8080})
print(config.host)    -- localhost
-- config.port = 99   -- خطا! فقط‌خواندنی

مقدار پیش‌فرض برای جدول

local function withDefault(default)
return setmetatable({}, {
__index = function() return default end
})
end

local counters = withDefault(0)
counters["الف"] = counters["الف"] + 1   -- 0 + 1 = 1
counters["الف"] = counters["الف"] + 1   -- 1 + 1 = 2
print(counters["الف"])   -- 2
print(counters["ب"])     -- 0 (پیش‌فرض)
الگوی __index دقیقاً همان چیزی است که وراثت در لوا را ممکن می‌کند — در مبحث کلاس‌ها خواهیم دید!

این مبحث بخشی از دوره آموزش کامل لوا است.

ابزارهای مرتبط