0Pricing
Lua Academy · درس

الطرق الوصفية الحسابية

أعد تعريف + و- و* و/ والمعاملات الأخرى باستخدام الطرق الوصفية

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

أسماء دوال الميتا

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

-- Operator -> Metamethod
-- a + b    -> __add
-- a - b    -> __sub
-- a * b    -> __mul
-- a / b    -> __div
-- a % b    -> __mod
-- a ^ b    -> __pow
-- a // b   -> __idiv
-- -a       -> __unm (unary minus)
-- #a       -> __len
print("Metamethods defined for all Lua operators")

__add لجمع المتجهات

عرّف __add في جدول المتجه لدعم العامل +. تستقبل دالة الميتا معاملين وتعيد قيمة جديدة. وقد يكون كلا المعاملين جدولين أو قد يكون أحدهما عددًا، لذا ينبغي أن تتعامل دالة الميتا مع كلتا الحالتين.

local Vec = {}
Vec.__index = Vec

Vec.__add = function(a, b)
  return setmetatable({x=a.x+b.x, y=a.y+b.y}, Vec)
end

Vec.__tostring = function(v)
  return string.format("Vec(%g,%g)", v.x, v.y)
end

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

local v1 = Vec.new(1,2)
local v2 = Vec.new(3,4)
print(tostring(v1 + v2))   -- Vec(4,6)

__sub و__mul و__div

عرّف __sub و__mul و__div بالطريقة نفسها. وبالنسبة إلى الضرب، تعامل مع حالتي table*table وtable*number من خلال التحقق من نوعي المعاملين داخل دالة الميتا.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__sub = function(a,b) return V(a.x-b.x, a.y-b.y) end
Vec.__mul = function(a,b)
  if type(a)=="number" then return V(a*b.x, a*b.y)
  elseif type(b)=="number" then return V(a.x*b, a.y*b)
  else return a.x*b.x + a.y*b.y  -- dot product
  end
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end

local v = V(3,4)
print(tostring(v * 2))    -- (6,8)
print(tostring(V(1,0) - V(0,1)))  -- (1,-1)

__unm للنفي الأحادي

__unm هي دالة ميتا للنفي الأحادي، وتُستدعى عندما تقيّم Lua التعبير -obj. وهي تستقبل المعامل، وتُمرَّر إليها القيمة نفسها مرتين للاتساق، ثم تعيد القيمة المنفية.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__unm = function(a) return V(-a.x, -a.y) end
Vec.__tostring = function(v)
  return string.format("(%g,%g)", v.x, v.y)
end

local v = V(3, -4)
print(tostring(-v))    -- (-3,4)
print(tostring(-(-v))) -- (3,-4)

__len للطول المخصص

يُستدعى __len عند تقييم #obj على جدول لا يحتوي على تسلسل صحيح خام. عرّفه ليعيد «طولًا» ذا معنى للأنواع المخصصة مثل المجموعات أو الطوابير أو الحاويات الموزونة.

local Bag = {}
Bag.__index = Bag
Bag.__len = function(b) return b._count end

function Bag.new()
  return setmetatable({_count=0, _items={}}, Bag)
end
function Bag:add(item, qty)
  self._items[item] = (self._items[item] or 0) + (qty or 1)
  self._count = self._count + (qty or 1)
end

local bag = Bag.new()
bag:add("apple", 3)
bag:add("banana", 2)
print(#bag)   -- 5

__mod و__pow

يتعامل __mod مع العامل %، بينما يتعامل __pow مع العامل ^. وهما أقل شيوعًا، لكنهما مفيدان للأنواع العددية المخصصة مثل الأعداد الصحيحة الكبيرة والكسور أو كائنات الحساب المعياري.

local Modular = {}
Modular.__index = Modular
local M = 1000000007

local function mod(n)
  return setmetatable({n = n % M}, Modular)
end

Modular.__add = function(a,b) return mod(a.n + b.n) end
Modular.__mul = function(a,b) return mod(a.n * b.n) end
Modular.__pow = function(a,b)
  local r, base, exp = mod(1), a, b
  while exp > 0 do
    if exp%2==1 then r = r*base end
    base = base*base; exp = math.floor(exp/2)
  end
  return r
end

print((mod(2) ^ 30).n)   -- 73741817 (2^30 mod 1e9+7)

__concat

يُفعَّل __concat بواسطة العامل .. عندما يملك أحد المعاملين على الأقل دالة الميتا هذه. ويتيح لك ذلك تعريف التسلسل للأنواع المخصصة أو إنشاء لغات خاصة بالمجال ذات أسلوب متسلسل.

local Builder = {}
Builder.__index = Builder
Builder.__concat = function(a, b)
  local result = {}
  for _, v in ipairs(a._parts) do result[#result+1] = v end
  if type(b) == "string" then result[#result+1] = b
  else for _, v in ipairs(b._parts) do result[#result+1] = v end end
  return setmetatable({_parts=result}, Builder)
end
Builder.build = function(b) return table.concat(b._parts) end

local function S(s) return setmetatable({_parts={s}},Builder) end
print((S("Hello") .. ", " .. S("World") .. "!"):build())

دوال ميتا للمقارنة

يعرّف __eq العامل == للجداول، ولا يُستدعى إلا عندما يملك المعاملان جدول الميتا نفسه. ويعرّف __lt العامل <، بينما يعرّف __le العامل <=. ملاحظة: يستخدم ~= الدالة __eq؛ ويستخدم > الدالة __lt مع عكس المعاملين؛ ويستخدم >= الدالة __le.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end

Vec.__eq = function(a,b) return a.x==b.x and a.y==b.y end
Vec.__lt = function(a,b)
  return (a.x^2+a.y^2) < (b.x^2+b.y^2)  -- by magnitude
end

print(V(1,2) == V(1,2))  -- true
print(V(1,2) == V(1,3))  -- false
print(V(1,0) < V(2,0))   -- true (1 < 2)

تسلسل دوال الميتا

بما أن دوال الميتا تعيد قيمًا، عادةً جداول جديدة، يمكن تسلسل العمليات بصورة طبيعية. يعيد كل عامل كائنًا جديدًا، ويستخدم العامل التالي تلك النتيجة. ويتيح ذلك كتابة تعبيرات حسابية متسلسلة على الأنواع المخصصة.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__add = function(a,b) return V(a.x+b.x,a.y+b.y) end
Vec.__mul = function(a,b)
  if type(b)=="number" then return V(a.x*b,a.y*b) end
  return V(a.x*b.x+a.y*b.y, 0)   -- simplified
end
Vec.__tostring=function(v) return "("..v.x..","..v.y..")" end

local result = V(1,0) + V(0,1) * 3
print(tostring(result))   -- (1,3)

العمليات على الأنواع المختلطة

عند كتابة vec * 2، يكون المعامل الأيسر هو الجدول. وعند كتابة 2 * vec، يكون المعامل الأيسر عددًا، ولا يملك دالة ميتا، لذلك تتحقق Lua من جدول ميتا المعامل الأيمن بحثًا عن __mul. تعامل مع الترتيبين كليهما في دالة الميتا.

local Vec = {}
Vec.__index = Vec
local function V(x,y) return setmetatable({x=x,y=y},Vec) end
Vec.__tostring = function(v) return "("..v.x..","..v.y..")" end

Vec.__mul = function(a, b)
  if type(a) == "number" then
    return V(a*b.x, a*b.y)   -- scalar * vec
  elseif type(b) == "number" then
    return V(a.x*b, a.y*b)   -- vec * scalar
  end
  return a.x*b.x + a.y*b.y  -- dot product
end

print(tostring(V(1,2) * 3))  -- (3,6)
print(tostring(3 * V(1,2)))  -- (3,6)

تحقق سريع

ما دالة الميتا التي يفعّلها التعبير -myTable؟

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

الملخص:

  • __add __sub __mul __div __mod __pow __idiv — الحساب الثنائي
  • __unm — النفي الأحادي؛ __len — العامل #
  • __concat — العامل ..
  • __eq __lt __le — عوامل المقارنة
  • تعامل مع الأنواع المختلطة، العدد/الجدول، داخل دوال الميتا

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

هل درس «الطرق الوصفية الحسابية» مجاني؟

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

ماذا ستتعلم في «الطرق الوصفية الحسابية»؟

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

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

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

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

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

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

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

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

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