متاجدولها (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 دقیقاً همان چیزی است که وراثت در لوا را ممکن میکند — در مبحث کلاسها خواهیم دید!این مبحث بخشی از دوره آموزش کامل لوا است.