الـ Metamethod المسماة __newindex
جزء من قسم المنطق وتسلسل التنفيذ في رحلة Lua على Coddy. الدرس 19 من 54.
لقد تعلّمت كيف يتحكّم __index فيما يحدث عندما تحاول قراءة مفتاح غير موجود في جدول. والآن ستكتشف نظيره: __newindex، الذي يتحكّم فيما يحدث عندما تُسنِد قيمة إلى مفتاح لم يتضمّنه الجدول بعد.
تُستدعى الطريقة الوصفية __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
player.health = "high" -- لا تظهر رسالة: health موجودة الآنلاحظ استخدام rawset() في المثال الثاني. تتجاوز هذه الدالة الجدول الفوقي وتضبط القيمة مباشرةً في الجدول.
من دونه، سيؤدي تعيين القيمة إلى تشغيل __newindex مرة أخرى، ما ينشئ حلقة لا نهائية.
بما أن __newindex لا يعمل إلا مع المفاتيح غير الموجودة في الجدول، فإن هذا الفحص يحمي الإسناد الأول لكل مفتاح. بعد أن يخزّن rawset القيمة health، تغيّر الإسنادات اللاحقة قيمته مباشرةً. للتحقق من كل إسناد، اترك الجدول نفسه فارغًا وخزّن القيم في جدول ثانٍ يقرأ منه عبر __index:
local data = {}
local player = setmetatable({}, {
__index = data,
__newindex = function(t, key, value)
if key == "health" and type(value) ~= "number" then
print("Health must be a number!")
else
data[key] = value
end
end
})
player.health = 100
player.health = "high" -- المخرجات: Health must be a number!
print(player.health) -- المخرجات: 100لا يحصل player على مفتاح خاص به أبدًا، لذا تمر كل عملية إسناد عبر __newindex، وكل عملية قراءة تصل إلى data عبر __index.
التحدي
سهلاكتب دالة createValidatedTable تأخذ key وvalue وتُعيد جدولًا لا يقبل إلا القيم النصية للمفاتيح الجديدة.
أنشئ جدولًا فارغًا وأرفق به جدولًا وصفيًا يحتوي على __newindex للتحقق من نوع القيمة. إذا حاول أحدهم إضافة قيمة غير نصية، فاستخدم rawset() لتخزين النص "invalid" بدلًا منها. أما القيم النصية، فخزّنها بشكل عادي باستخدام rawset().
المنطق:
- أنشئ جدولًا فارغًا
- أنشئ جدولًا وصفيًا يحتوي على
__newindexيستقبل الجدول والمفتاح والقيمة - داخل
__newindex، تحقّق مما إذا كانت القيمة نصية باستخدامtype(value) == "string" - إذا كانت نصية، فاستخدم
rawset(t, key, value)لتخزينها - إذا لم تكن نصية، فاستخدم
rawset(t, key, "invalid")لتخزين"invalid"بدلًا منها - أرفق الجدول الوصفي بالجدول باستخدام
setmetatable() - استخدم
rawset()لإضافة زوج المفتاح والقيمة الأولي إلى الجدول (متجاوزًا الجدول الوصفي) - أعِد الجدول
المعاملات:
key(نص): المفتاح الأولي المراد إضافته إلى الجدولvalue(نص): القيمة الأولية المراد إضافتها إلى الجدول
القيمة المُعادة: جدول يتحقق من القيم ولا يقبل إلا القيم النصية، ويحتوي على زوج المفتاح والقيمة الأولي (جدول)
جرّب بنفسك
function createValidatedTable(key, value)
-- اكتب الكود هنا
end
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس المنطق وتسلسل التنفيذ
1التكرار المتقدم عبر الجداول
التكرار باستخدام pairs()التكرار باستخدام ipairs()pairs() مقابل ipairs()مراجعة - ورقة الشخصية4مقدمة إلى Metatables
ما هو الـ Metatable؟setmetatable و getmetatableالـ Metamethod المسماة __indexالـ Metamethod المسماة __newindexالـ Metamethod المسماة __tostringالـ Metamethods الحسابية - الجزء الأولالـ Metamethods الحسابية - الجزء الثانيملخص - جدول للقراءة فقط2المزيد من دوال مكتبة Table
table.concat()إنشاء الجداول و unpack()table.sort()فرز مخصص باستخدام الدوالمراجعة - لوحة أعلى النتائجتدرّب بنفسك: مترجم Lua عبر الإنترنت