Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الـ Metamethod المسماة __newindex

جزء من قسم Logic & Flow في رحلة Lua على Coddy — الدرس 19 من 54.

لقد تعلمت كيف يتحكم __index فيما يحدث عندما تحاول قراءة مفتاح غير موجود في جدول. الآن ستكتشف نظيره: __newindex، والذي يتحكم فيما يحدث عندما تحاول إضافة أو تعديل زوج مفتاح-قيمة.

يتم استدعاء الأسلوب الوصفي (metamethod) __newindex كلما حاولت تعيين قيمة لمفتاح غير موجود حالياً في الجدول. يمنحك هذا القدرة على اعتراض التعديلات والتحكم فيها قبل حدوثها.

إليك مثال بسيط يمنع إضافة أي مفاتيح جديدة إلى جدول:

local readOnly = {}
local meta = {
    __newindex = function(table, key, value)
        print("Cannot add key: " .. key)
    end
}

setmetatable(readOnly, meta)

readOnly.name = "Alice"  -- المخرجات: Cannot add key: name
print(readOnly.name)     -- المخرجات: nil

عندما تحاول تعيين readOnly.name = "Alice"، يرى Lua أن name غير موجود في الجدول. وبدلاً من إضافته، يقوم Lua باستدعاء الدالة __newindex بثلاثة وسائط: الجدول نفسه، والمفتاح الذي يتم تعيينه، والقيمة التي يتم إسنادها.

في هذا المثال، تقوم الدالة ببساطة بطباعة رسالة ولا تقوم بتخزين أي شيء في الواقع.

يمكنك أيضًا استخدام __newindex للتحقق من صحة البيانات قبل السماح بدخولها إلى جدولك:

local player = {}
local meta = {
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            rawset(t, key, value)
        end
    end
}

setmetatable(player, meta)

player.health = "high"  -- المخرجات: Health must be a number!
player.health = 100     -- مسموح به

لاحظ استخدام rawset() في المثال الثاني. تتجاوز هذه الدالة الـ metatable وتقوم بتعيين القيمة مباشرة في الجدول.

بدونها، سيؤدي تعيين القيمة إلى استدعاء __newindex مرة أخرى، مما يتسبب في حلقة لا نهائية.

challenge icon

التحدي

سهل

اكتب دالة createValidatedTable تأخذ key و value وتعيد جدولاً يقبل فقط قيم السلسلة النصية (string) للمفاتيح الجديدة.

قم بإنشاء جدول فارغ وأرفق به جدولاً وصفياً (metatable) باستخدام __newindex للتحقق من نوع القيمة. إذا حاول شخص ما إضافة قيمة ليست سلسلة نصية، استخدم rawset() لتخزين السلسلة "invalid" بدلاً من ذلك. بالنسبة لقيم السلسلة النصية، قم بتخزينها بشكل طبيعي باستخدام rawset().

المنطق:

  • قم بإنشاء جدول فارغ
  • قم بإنشاء جدول وصفي (metatable) باستخدام __newindex يستقبل الجدول، والمفتاح، والقيمة
  • داخل __newindex، تحقق مما إذا كانت القيمة سلسلة نصية باستخدام type(value) == "string"
  • إذا كانت سلسلة نصية، استخدم rawset(t, key, value) لتخزينها
  • إذا لم تكن سلسلة نصية، استخدم rawset(t, key, "invalid") لتخزين "invalid" بدلاً من ذلك
  • أرفق الجدول الوصفي بالجدول باستخدام setmetatable()
  • استخدم rawset() لإضافة زوج المفتاح والقيمة الأولي إلى الجدول (بتجاوز الجدول الوصفي)
  • أعد الجدول

المعاملات:

  • key (string): المفتاح الأولي لإضافته إلى الجدول
  • value (string): القيمة الأولية لإضافتها إلى الجدول

المخرجات: جدول مع التحقق من الصحة يقبل فقط قيم السلسلة النصية، ويحتوي على زوج المفتاح والقيمة الأولي (table)

ورقة مرجعية

يتم استدعاء الميثود الميتا (metamethod) __newindex عندما تحاول تعيين قيمة لمفتاح غير موجود في جدول، مما يسمح لك باعتراض التعديلات والتحكم فيها.

مثال أساسي لمنع إضافة مفاتيح جديدة:

local readOnly = {}
local meta = {
    __newindex = function(table, key, value)
        print("Cannot add key: " .. key)
    end
}

setmetatable(readOnly, meta)

readOnly.name = "Alice"  -- المخرجات: Cannot add key: name
print(readOnly.name)     -- المخرجات: nil

تستقبل الدالة __newindex ثلاث وسائط: الجدول نفسه، والمفتاح الذي يتم تعيينه، والقيمة التي يتم إسنادها.

التحقق من صحة البيانات باستخدام __newindex:

local player = {}
local meta = {
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            rawset(t, key, value)
        end
    end
}

setmetatable(player, meta)

player.health = "high"  -- المخرجات: Health must be a number!
player.health = 100     -- مسموح به

استخدم rawset(t, key, value) لتجاوز الجدول الميتا (metatable) وتعيين القيم مباشرة في الجدول. هذا يمنع الحلقات اللانهائية عند تعيين القيم داخل __newindex.

جرّب بنفسك

function createValidatedTable(key, value)
    -- اكتب الكود هنا
end
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Logic & Flow