0Pricing
Lua Academy · درس

مقدمة إلى جداول البيانات الوصفية

عيّن جداول البيانات الوصفية واحصل عليها باستخدام setmetatable/getmetatable

مقدمة إلى جداول البيانات الوصفية درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.

ما هو الجدول الفوقي؟

الجدول الفوقي هو جدول Lua عادي يتحكم في سلوك جدول آخر. عندما تواجه Lua عملية لا يمكنها تنفيذها على جدول (مثل العمليات الحسابية أو فهرسة مفتاح مفقود)، تبحث عن دالة فوقية مقابلة في الجدول الفوقي. وهذه هي آلية Lua لتوسعة اللغة من أجل التحميل الزائد للمعاملات والبرمجة كائنية التوجه.

local t = {}
local mt = {__index = function(_, k) return "default_" .. k end}

setmetatable(t, mt)

print(t.foo)    -- default_foo
print(t.bar)    -- default_bar
print(t[1])     -- default_1

setmetatable وgetmetatable

تضبط setmetatable(t, mt) الجدول الفوقي لـ t ليصبح mt، ثم تُرجع t. وتُرجع getmetatable(t) الجدول الفوقي، أو nil إذا لم يوجد. يمكنك حماية الجدول الفوقي من التغيير بتعيين mt.__metatable = "protected".

local t = {x = 10}
local mt = {}

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

-- Protect metatable
mt.__metatable = "locked"
print(getmetatable(t))   -- locked
-- setmetatable(t, {})  -- ERROR: cannot change protected metatable

__index كجدول

عندما يكون __index جدولًا، تبحث Lua عن المفتاح المفقود في ذلك الجدول. وهذا هو الأساس لتوريث النماذج الأولية في Lua. وإذا لم يكن المفتاح موجودًا في __index أيضًا، تتحقق Lua من جدوله الفوقي، وهكذا صعودًا في السلسلة.

local Animal = {sound = "...", legs = 4}

local Dog = setmetatable({sound = "Woof"}, {__index = Animal})
local Cat = setmetatable({sound = "Meow"}, {__index = Animal})

print(Dog.sound)   -- Woof (own field)
print(Dog.legs)    -- 4 (from Animal)
print(Cat.sound)   -- Meow
print(Cat.legs)    -- 4

__index كدالة

عندما يكون __index دالة، تستدعيها Lua مع الجدول والمفتاح المفقود. ويمكن للدالة حساب القيمة أو جلبها ديناميكيًا. أعد nil من __index للإشارة إلى "المفتاح غير موجود".

local dynamic = setmetatable({}, {
  __index = function(t, k)
    if k:sub(1,4) == "get_" then
      local field = k:sub(5)
      return function(self) return self[field] end
    end
    return nil
  end
})

dynamic.name = "Lua"
local getter = dynamic.get_name
print(getter(dynamic))   -- Lua

rawget وrawset

تقرأ rawget(t, k) مفتاحًا من جدول من دون تشغيل __index. وتعيّن rawset(t, k, v) مفتاحًا من دون تشغيل __newindex. استخدمهما لتجاوز الدوال الفوقية عند الحاجة إلى الوصول المباشر إلى الجدول داخل دالة فوقية، وذلك لتجنب الاستدعاء التكراري اللانهائي.

local logged = setmetatable({}, {
  __newindex = function(t, k, v)
    print("Setting", k, "=", v)
    rawset(t, k, v)  -- bypass __newindex
  end
})

logged.x = 10   -- Setting x = 10
logged.x = 20   -- no log! key now exists in t
print(logged.x) -- 20

مشاركة جداول متعددة لجدول ميتا واحد

يمكن مشاركة جدول ميتا واحد بين العديد من الجداول. هذه هي الطريقة التي تعمل بها أنظمة الفئات في Lua: تشترك جميع مثيلات الفئة في جدول الميتا نفسه، الذي يحتوي على الأساليب. وتؤثر التغييرات التي تُجرى على جدول الميتا في جميع المثيلات.

local Mt = {
  __index = {
    greet = function(self)
      print("Hello from " .. (self.name or "?"))
    end
  }
}

local a = setmetatable({name="Alice"}, Mt)
local b = setmetatable({name="Bob"},   Mt)

a:greet()   -- Hello from Alice
b:greet()   -- Hello from Bob

حقل __metatable

يؤدي تعيين mt.__metatable إلى أي قيمة إلى جعل getmetatable يعيد تلك القيمة بدلًا من جدول الميتا الحقيقي. ويمنع ذلك المستخدمين من فحص جدول الميتا أو استبداله، وهو أمر مفيد للتغليف والأمان.

local secret = setmetatable({}, {
  __metatable = false,    -- hide metatable
  __index = {value = 42}
})

print(secret.value)        -- 42
print(getmetatable(secret)) -- false (not the real mt)
-- setmetatable(secret, {}) -- ERROR

التحقق من جدول الميتا

استخدم getmetatable(t) للتحقق مما إذا كان لكائن ما جدول ميتا محدد، وذلك لفحص النوع. وبما أن __metatable يمكن أن يحجب جدول الميتا الحقيقي، فاستخدم rawequal أو حقلًا مميزًا لإجراء عمليات تحقق موثوقة من نوع المثيل.

local MyClass = {}
MyClass.__index = MyClass
MyClass.__metatable = MyClass   -- use self as marker

function MyClass.new(x)
  return setmetatable({x=x}, MyClass)
end

local obj = MyClass.new(5)
print(getmetatable(obj) == MyClass)   -- true
print(obj.x)                           -- 5

جداول الميتا لغير الجداول

تملك السلاسل النصية في Lua جدول ميتا مسبقًا، وهو وحدة string. لذلك يمكنك استدعاء s:upper() على أي سلسلة نصية. ولا يمكنك تعيين جداول ميتا للسلاسل النصية أو الأعداد أو القيم المنطقية باستخدام Lua الخالصة، بل للجداول وuserdata فقط.

local s = "hello"
local mt = getmetatable(s)

-- String metatable has __index = string library
print(mt.__index == string)   -- true

-- So all string functions are methods:
print(s:upper())              -- HELLO
print(s:rep(3, "-"))          -- hello-hello-hello

تصحيح الأخطاء باستخدام جداول الميتا

يمكنك إضافة دالة التحويل __tostring للتحكم في طريقة عرض الجدول بواسطة tostring() وprint(). وهذا مفيد للغاية عند تصحيح أخطاء الكائنات المعقدة.

local Point = {}
Point.__index = Point
Point.__tostring = function(p)
  return string.format("Point(%g, %g)", p.x, p.y)
end

function Point.new(x, y)
  return setmetatable({x=x,y=y}, Point)
end

local p = Point.new(3, 4)
print(tostring(p))   -- Point(3, 4)
print(p)             -- Point(3, 4)  (print calls tostring)

تحقق سريع

ماذا يحدث عند الوصول إلى مفتاح غير موجود في جدول يملك جدول ميتا، مع تعيين __index إلى جدول آخر؟

مراجعة: جداول الميتا

الملخص:

  • setmetatable(t, mt) / getmetatable(t)
  • __index: جدول ← البحث في النموذج الأولي؛ دالة ← الإرسال الديناميكي
  • تتجاوز rawget/rawset دوال الميتا
  • تتيح جداول الميتا المشتركة سلوكًا شبيهًا بالفئات
  • يحمي __metatable جدول الميتا من الفحص
  • يتحكم __tostring في مخرجات الطباعة

الأسئلة الشائعة

هل درس «مقدمة إلى جداول البيانات الوصفية» مجاني؟

نعم — نص درس «مقدمة إلى جداول البيانات الوصفية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.

ماذا ستتعلم في «مقدمة إلى جداول البيانات الوصفية»؟

عيّن جداول البيانات الوصفية واحصل عليها باستخدام setmetatable/getmetatable تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟

لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «مقدمة إلى جداول البيانات الوصفية»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟

نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. مقدمة إلى جداول البيانات الوصفية
  2. ‏__index و__newindex
  3. الطرق الوصفية الحسابية
  4. ‏__tostring و__len
← العودة إلى Lua Academy