0Pricing
Lua Academy · درس

أساليب النسخ وself

عرّف الأساليب باستخدام صياغة النقطتين ومعامل self الضمني

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

self هي النسخة

عند استدعاء obj:method()، تمرر Lua القيمة obj تلقائيًا بوصفها المعامل الأول. ووفقًا للعرف، يُسمى هذا المعامل self. ومن خلال self، يصل الأسلوب إلى بيانات النسخة ويستدعي أساليب أخرى.

local Counter = {}
Counter.__index = Counter

function Counter.new(start)
  return setmetatable({value=start or 0, step=1}, Counter)
end

function Counter:increment()
  self.value = self.value + self.step
end

function Counter:getValue() return self.value end

local c = Counter.new(10)
c:increment(); c:increment()
print(c:getValue())  -- 12

تسلسل الأساليب

أعد self من الأساليب لإتاحة التسلسل: obj:method1():method2():method3(). يعيد كل استدعاء الكائن نفسه، مما يتيح أسلوبًا انسيابيًا. ويعمل ذلك بأفضل صورة مع الأساليب التي تعدّل الحالة.

local Builder = {}
Builder.__index = Builder

function Builder.new()
  return setmetatable({parts={}},Builder)
end

function Builder:add(s) self.parts[#self.parts+1]=s; return self end
function Builder:addAll(t)
  for _,v in ipairs(t) do self.parts[#self.parts+1]=v end
  return self
end
function Builder:build() return table.concat(self.parts," ") end

local result = Builder.new()
  :add("Hello")
  :add("from")
  :addAll({"Lua","OOP"})
  :build()
print(result)  -- Hello from Lua OOP

استدعاء أساليب أخرى

يمكن للأساليب استدعاء أساليب أخرى على النسخة نفسها عبر self:otherMethod(). ويعزز ذلك إعادة استخدام الشفرة داخل الصنف. ويمكن أن تكون الدوال المساعدة الخاصة دوالًا محلية عادية تتلقى self صراحةً.

local Stack = {}
Stack.__index = Stack

function Stack.new() return setmetatable({_data={},_size=0},Stack) end
function Stack:push(v) self._size=self._size+1; self._data[self._size]=v end
function Stack:pop()
  if self:isEmpty() then return nil end
  local v=self._data[self._size]; self._data[self._size]=nil
  self._size=self._size-1; return v
end
function Stack:peek()
  return not self:isEmpty() and self._data[self._size] or nil
end
function Stack:isEmpty() return self._size==0 end
function Stack:size() return self._size end

local s=Stack.new(); s:push(1);s:push(2);s:push(3)
print(s:pop(),s:peek(),s:size())  -- 3  2  2

تحذير بشأن تجاوز الأساليب

يؤدي تعيين حقل في النسخة بالاسم نفسه لأسلوب في الصنف إلى حجب الأسلوب لهذه النسخة. ويكون ذلك خطأً عادةً — لذا انتبه عندما يمكن أن تتعارض أسماء حقول النسخة مع أسماء الأساليب.

local Dog = {}
Dog.__index = Dog
function Dog.new(n) return setmetatable({name=n},Dog) end
function Dog:speak() print(self.name..": Woof!") end

local d = Dog.new("Rex")
d:speak()        -- Rex: Woof!

-- Accidental shadow:
d.speak = "loud"  -- now d.speak is a string, not a function
local ok,err = pcall(function() d:speak() end)
print(ok, err)   -- false  attempt to call a string value

self في دوال الاستدعاء اللاحق

يؤدي تمرير أسلوب بوصفه دالة استدعاء لاحق إلى فقدان self الضمني. غلّف الأسلوب داخل إغلاق لالتقاط self.

local Timer = {}
Timer.__index = Timer
function Timer.new(n) return setmetatable({count=n},Timer) end
function Timer:tick()
  self.count=self.count-1
  print("Ticking, count:", self.count)
end

local t = Timer.new(3)

-- Wrong: loses self
-- local cb = t.tick  -- cb(t) works but cb() doesn't

-- Correct: closure captures self
local cb = function() t:tick() end
cb(); cb(); cb()  -- Ticking 3 times

الأساليب الساكنة مقابل أساليب النسخ

يُستدعى الأسلوب الساكن على الصنف، لا على نسخة. ولا يحتوي على self (أو يتلقى الصنف بوصفه self). لا يوجد في Lua تمييز رسمي بينهما — ووفقًا للعرف، استخدم . (وليس :) للأساليب الساكنة.

local MathUtils = {}
MathUtils.__index = MathUtils

-- Static method (no instance needed)
function MathUtils.clamp(v, lo, hi)
  return math.max(lo, math.min(hi, v))
end

-- Instance method (needs self)
function MathUtils:scale(factor)
  self.value = self.value * factor
end

print(MathUtils.clamp(15, 0, 10))  -- 10
local m = setmetatable({value=5},MathUtils)
m:scale(3)
print(m.value)  -- 15

أساليب Mixin

أضف أساليب من جدول Mixin إلى صنف دون توارث رسمي. وهذا تركيب مسطح: انسخ دوال Mixin أو ارجع إليها داخل جدول الصنف.

local Serializable = {}
function Serializable:serialize()
  local parts={}
  for k,v in pairs(self) do
    if type(v)~="function" then
      parts[#parts+1]=k.."="..tostring(v)
    end
  end
  return "{"..table.concat(parts,",").."}"
end

local User = {}
User.__index = User
User.serialize = Serializable.serialize   -- mixin!

function User.new(n,a) return setmetatable({name=n,age=a},User) end

local u = User.new("Alice",30)
print(u:serialize())

الأساليب المجرّدة

لا تفرض Lua الأساليب المجرّدة، ولكن يمكنك تعريف أسلوب في صنف أساسي يرفع خطأً، مما يجبر الأصناف الفرعية على تجاوزه. وهذا عرف يدل على أن الأسلوب "يجب تجاوزه".

local Shape = {}
Shape.__index = Shape

function Shape.new() return setmetatable({},Shape) end

function Shape:area()
  error(type(self).." must implement area()",2)
end

function Shape:describe()
  print("Shape area:", self:area())
end

local sq={}
setmetatable(sq,{__index=Shape})
function sq:area() return 4*4 end

sq:describe()  -- Shape area: 16

جداول الأساليب

بالنسبة إلى الأصناف التي تحتوي على أساليب كثيرة، نظّم الأساليب في مجموعات حسب الوظيفة. تشترك جميع الأساليب في الجدول نفسه في البحث عبر جدول البيانات الوصفية نفسه، ولكن يمكنك تقسيمها حسب الاهتمام باستخدام مساحات أسماء فرعية.

local Entity = {}
Entity.__index = Entity

Entity.Physics = {}
function Entity.Physics:applyForce(fx,fy)
  self.vx=(self.vx or 0)+fx
  self.vy=(self.vy or 0)+fy
end

Entity.Render = {}
function Entity.Render:draw()
  print(string.format("Draw at (%g,%g)",self.x or 0,self.y or 0))
end

-- Mix into main class
for k,v in pairs(Entity.Physics) do Entity[k]=v end
for k,v in pairs(Entity.Render) do Entity[k]=v end

function Entity.new(x,y) return setmetatable({x=x,y=y},Entity) end
local e=Entity.new(10,20); e:draw(); e:applyForce(5,0); print(e.vx)

التفويض مقابل التوارث

فضّل التفويض (الاحتفاظ بمرجع) على سلاسل التوارث العميقة. يمكن للصنف أن يفوّض إلى كائن آخر بدلًا من التوارث منه، مما يحافظ على انخفاض الترابط ويبقي كل صنف مركزًا على مهمته.

local Logger = {}
Logger.__index = Logger
function Logger.new(name) return setmetatable({name=name},Logger) end
function Logger:log(msg) print("["..self.name.."] "..msg) end

local Service = {}
Service.__index = Service

function Service.new(name)
  return setmetatable({
    name=name,
    logger=Logger.new(name)  -- delegation
  },Service)
end

function Service:start()
  self.logger:log("starting...")  -- delegate logging
  print(self.name, "running")
end

Service.new("AuthService"):start()

تحقق سريع

ما الفرق بين obj:method() وobj.method()؟

مراجعة: أساليب النسخ

الملخص:

  • صيغة الاستدعاء باستخدام النقطتين: obj:method() == obj.method(obj)
  • أعد self لإتاحة تسلسل الأساليب
  • استدعِ أساليب أخرى: self:otherMethod()
  • دوال الاستدعاء اللاحق: غلّفها في إغلاق للحفاظ على self
  • الأساليب الساكنة: استخدم تدوين النقطة وفقًا للعرف
  • فضّل التفويض على التوارث العميق لتحقيق المرونة

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

هل درس «أساليب النسخ وself» مجاني؟

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

ماذا ستتعلم في «أساليب النسخ وself»؟

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

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

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

كم من الوقت يستغرق درس «أساليب النسخ وself»؟

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

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

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

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

  1. الفئات عبر جداول البيانات الوصفية
  2. المنشئات وnew()
  3. أساليب النسخ وself
  4. التغليف باستخدام الإغلاقات
← العودة إلى Lua Academy