المنشئات وnew()
اكتب دوال منشئة تنشئ النسخ وتهيّئها
المنشئات وnew() درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.
مسؤولية المُنشئ
ينشئ المُنشئ نسخةً ويهيّئها. ويتلقى القيم الأولية، ويتحقق من صحتها، ويعيّن القيم الافتراضية للحقول المفقودة، ثم يعيد النسخة الجديدة. يضمن المُنشئ المصمم جيدًا أن تبدأ كل نسخة بحالة صالحة.
local Player = {}
Player.__index = Player
function Player.new(name, hp, mp)
assert(type(name)=="string" and name~="","need name")
return setmetatable({
name = name,
hp = hp or 100,
mp = mp or 50,
alive = true,
items = {},
}, Player)
end
local p = Player.new("Hero")
print(p.name, p.hp, p.mp) -- Hero 100 50المُنشئ الانسيابي
يعيد المُنشئ الانسيابي self من أساليب التعيين، مما يتيح تسلسل الأساليب أثناء الإنشاء. وهذا هو نمط الباني في Lua.
local Config = {}
Config.__index = Config
function Config.new()
return setmetatable({_data={}}, Config)
end
function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end
local cfg = Config.new()
:set("host","localhost")
:set("port",8080)
:set("debug",true)
:build()
print(cfg.host, cfg.port)مُنشئ النسخ
ينشئ مُنشئ النسخ نسخةً جديدة بالقيم نفسها الموجودة في نسخة أخرى. مهم: استخدم النسخ السطحي أو العميق بحسب ما إذا كان ينبغي مشاركة الجداول المتداخلة أو جعلها مستقلة.
local function deepCopy(orig)
if type(orig)~="table" then return orig end
local copy = {}
for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
return setmetatable(copy, getmetatable(orig))
end
local Item = {}
Item.__index = Item
function Item.new(name, stats)
return setmetatable({name=name, stats=stats or {}}, Item)
end
function Item:clone()
return deepCopy(self)
end
local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage) -- 50 (unchanged)المُنشئ مع التحقق
تحقق دائمًا من مدخلات المُنشئ. اطرح أخطاءً وصفية عند وجود مدخلات غير صالحة في المستوى 2 (مع تحميل المستدعي المسؤولية). يكتشف ذلك الأخطاء مبكرًا وينتج رسائل خطأ مفيدة.
local Rectangle = {}
Rectangle.__index = Rectangle
function Rectangle.new(w, h)
assert(type(w)=="number" and w>0,"width must be positive number")
assert(type(h)=="number" and h>0,"height must be positive number")
return setmetatable({width=w, height=h}, Rectangle)
end
function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end
local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter()) -- 15 16نمط القيم الافتراضية
استخدم جدولًا للقيم الافتراضية لمعالجة معاملات المُنشئ الاختيارية بطريقة واضحة. ويجنبك ذلك سلاسل طويلة من x = x or default، ويجعل القيم الافتراضية صريحة وسهلة التغيير.
local Sprite = {}
Sprite.__index = Sprite
local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}
function Sprite.new(image, opts)
local cfg = opts or {}
local self = {image=image}
for k,v in pairs(DEFAULTS) do
self[k] = cfg[k] ~= nil and cfg[k] or v
end
return setmetatable(self, Sprite)
end
local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale) -- 100 200 1أساليب المصنع الساكنة
يمكن أن يحتوي الصنف على عدة أساليب مصنع لسيناريوهات إنشاء مختلفة. وهذا أوضح من تحميل مُنشئ واحد بعدد كبير من المعاملات الاختيارية.
local Color = {}
Color.__index = Color
function Color.fromRGB(r,g,b)
return setmetatable({r=r,g=g,b=b}, Color)
end
function Color.fromHex(hex)
hex = hex:gsub("#","")
return setmetatable({
r=tonumber(hex:sub(1,2),16),
g=tonumber(hex:sub(3,4),16),
b=tonumber(hex:sub(5,6),16),
}, Color)
end
function Color:toHex()
return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end
local red = Color.fromHex("#FF0000")
print(red:toHex()) -- #FF0000سجل المُنشئات
استخدم سجلًا لتتبع جميع النسخ. يتيح ذلك إجراء عمليات عامة مثل "تدمير الكل" أو تكرار جميع الكائنات من نوع معين.
local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}
function Enemy.new(name, hp)
local self = setmetatable({name=name, hp=hp}, Enemy)
Enemy._all[#Enemy._all+1] = self
return self
end
function Enemy.destroyAll()
for _, e in ipairs(Enemy._all) do
print("Destroying:", e.name)
end
Enemy._all = {}
end
Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all) -- 2
Enemy.destroyAll()التهيئة الكسولة
تكون بعض الحقول مكلفة حسابيًا. استخدم __index مع دالة لحسابها وتخزينها مؤقتًا عند أول وصول إليها.
local BigData = {}
BigData.__index = function(t, k)
if k == "processed" then
print("Computing processed...")
local result = {}
for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
rawset(t,"processed",result)
return result
end
end
function BigData.new(raw)
return setmetatable({raw=raw}, BigData)
end
local d = BigData.new({1,2,3,4,5})
print(d.processed[3]) -- Computing... 6
print(d.processed[3]) -- 6 (cached, no recompute)النموذج الأولي من نسخة
استنسخ نسخةً لإنشاء نسخة أخرى بالقيم الأساسية نفسها. يحصل الاستنساخ على جدول البيانات الوصفية نفسه (أي الصنف نفسه) ونسخة من بيانات النسخة. وهذا مفيد لكائنات "القوالب".
local Unit = {}
Unit.__index = Unit
function Unit.new(t)
return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end
function Unit:clone()
return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end
function Unit:__tostring()
return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end
local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))أمان أخطاء المُنشئ
إذا فشل الإنشاء في منتصفه (مثلًا عند تخصيص مورد)، فتأكد من عدم خروج كائنات غير مكتملة. استخدم pcall لالتقاط أخطاء الإنشاء وتنظيف الموارد عند الحاجة.
local FileHandle = {}
FileHandle.__index = FileHandle
function FileHandle.new(path, mode)
local f, err = io.open(path, mode or "r")
if not f then
return nil, "cannot open " .. path .. ": " .. err
end
return setmetatable({_f=f, path=path}, FileHandle)
end
function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end
local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
endتحقق سريع
ما دور المُنشئ (new()) في البرمجة كائنية التوجه في Lua؟
مراجعة: المُنشئات
الملخص:
- يتحقق المُنشئ من الصحة، ويهيّئ النسخة، ويستدعي setmetatable
- استخدم جدول القيم الافتراضية لمعالجة المعاملات الاختيارية بوضوح
- استخدم عدة أساليب مصنع لسيناريوهات الإنشاء المختلفة
- استخدم مُنشئ النسخ لكائنات القوالب
- استخدم التهيئة الكسولة عبر __index للحقول المكلفة حسابيًا
- أعد nil+err من المُنشئ عند الفشل (مثل فشل تخصيص الموارد)
الأسئلة الشائعة
هل درس «المنشئات وnew()» مجاني؟
نعم — نص درس «المنشئات وnew()» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.
ماذا ستتعلم في «المنشئات وnew()»؟
اكتب دوال منشئة تنشئ النسخ وتهيّئها تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟
لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «المنشئات وnew()»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟
نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.