__tostring و__len
تحكّم في التمثيل النصي ومعامل # عبر الطرق الوصفية
__tostring و__len درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.
دالة الميتا __tostring
تُستدعى __tostring عند استدعاء tostring(obj)، وكذلك بواسطة print()، التي تستدعي tostring لكل معامل. عرّفها لتوفير تمثيل مقروء للبشر للكائنات المخصصة.
local Point = {}
Point.__index = Point
Point.__tostring = function(p)
return string.format("Point(%.2f, %.2f)", p.x, p.y)
end
function Point.new(x,y)
return setmetatable({x=x,y=y}, Point)
end
local p = Point.new(3.14, 2.72)
print(p) -- Point(3.14, 2.72)
print(tostring(p)) -- Point(3.14, 2.72)__len للتسلسلات
يُستدعى __len عند تطبيق العامل # على جدول يملك دالة الميتا هذه. في Lua 5.2 والإصدارات الأحدث، يُستدعى __len دائمًا للجداول؛ أما في الإصدار 5.1 فلا يُستدعى إلا لـ userdata. استخدمه لتعريف «الطول» للحاويات المخصصة.
local Queue = {}
Queue.__index = Queue
Queue.__len = function(q) return q._tail - q._head + 1 end
function Queue.new()
return setmetatable({_data={},_head=1,_tail=0}, Queue)
end
function Queue:push(v)
self._tail = self._tail + 1
self._data[self._tail] = v
end
function Queue:pop()
if self._head > self._tail then return nil end
local v = self._data[self._head]
self._head = self._head + 1
return v
end
local q = Queue.new()
q:push("a"); q:push("b"); q:push("c")
print(#q) -- 3__tostring غني لتصحيح الأخطاء
يتضمن __tostring الجيد اسم النوع والحقول الأساسية. وبالنسبة إلى الكائنات المتداخلة، استدعِ tostring بصورة تكرارية. وهذا يجعل تصحيح الأخطاء أسهل بكثير من المخرجات الافتراضية مثل "table: 0x...".
local function tableToString(t, depth)
depth = depth or 0
if depth > 3 then return "{...}" end
local parts = {}
for k, v in pairs(t) do
if type(v) == "table" then
parts[#parts+1] = k.."="..tableToString(v, depth+1)
else
parts[#parts+1] = k.."="..tostring(v)
end
end
return "{"..table.concat(parts,", ").."}"
end
local obj = {name="test", data={x=1,y=2}, active=true}
print(tableToString(obj))__len مقابل العامل #
بالنسبة إلى الجداول التي لا تملك دالة ميتا __len، يبحث #t عن أي حد للتسلسل، حيث t[i] ~= nil وt[i+1] == nil. وعند وجود فجوات في الجدول، تكون النتيجة غير متوقعة. ويتيح __len تعريف طول موثوق ومتسق.
-- Table with hole: # is unpredictable
local t = {10, 20, nil, 40}
print(#t) -- could be 2 or 4, undefined!
-- Custom container with authoritative length
local SafeList = {}
SafeList.__index = SafeList
SafeList.__len = function(s) return s._size end
function SafeList.new()
return setmetatable({_data={}, _size=0}, SafeList)
end
function SafeList:add(v)
self._size = self._size + 1
self._data[self._size] = v
end
local s = SafeList.new()
s:add(1); s:add(nil); s:add(3)
print(#s) -- 3 (always correct)__tostring في رسائل الخطأ
عند استخدام كائنات الأخطاء، أي الجداول بدلًا من السلاسل النصية، يؤدي تعريف __tostring إلى جعل رسائل الخطأ مقروءة عندما ينتشر الخطأ ويُحوَّل إلى سلسلة نصية.
local function makeError(code, msg)
return setmetatable(
{code=code, message=msg},
{__tostring = function(e)
return string.format("Error[%d]: %s", e.code, e.message)
end}
)
end
local ok, err = pcall(function()
error(makeError(404, "resource not found"))
end)
if not ok then
-- err is the error object (table)
print(tostring(err)) -- may show table address...__tostring مع الوراثة
عند استخدام البرمجة كائنية التوجه القائمة على النماذج الأولية، عرّف __tostring في جدول ميتا الفئة. وستستخدم جميع المثيلات تلقائيًا دالة __tostring الخاصة بالفئة، لأن جدول ميتا المثيل هو جدول الفئة نفسه.
local Animal = {}
Animal.__index = Animal
Animal.__tostring = function(a)
return string.format("%s(%s)", a._type or "Animal", a.name or "?")
end
function Animal.new(name, atype)
return setmetatable({name=name, _type=atype}, Animal)
end
local cat = Animal.new("Whiskers", "Cat")
local dog = Animal.new("Rex", "Dog")
print(cat) -- Cat(Whiskers)
print(dog) -- Dog(Rex)تنفيذ Set باستخدام __len و__tostring
ادمج __len و__tostring في نوع واحد للحصول على تنفيذ كامل وسهل الاستخدام لـ Set.
local Set = {}
Set.__index = Set
Set.__len = function(s) return s._size end
Set.__tostring = function(s)
local items = {}
for k in pairs(s._data) do items[#items+1]=tostring(k) end
table.sort(items)
return "Set{" .. table.concat(items,", ") .. "}"
end
function Set.new(...)
local obj = setmetatable({_data={},_size=0}, Set)
for _, v in ipairs({...}) do
if not obj._data[v] then obj._data[v]=true; obj._size=obj._size+1 end
end
return obj
end
local s = Set.new(3,1,4,1,5,9,2,6)
print(#s) -- 7 (duplicates removed)
print(tostring(s)) -- Set{1, 2, 3, 4, 5, 6, 9}كائنات عددية باستخدام كليهما
أنشئ نوعًا للكسور يتيح __tostring عرضها، ويستخدم __len لعدد الأرقام أو لمقياس خاص بالمجال.
local Frac = {}
Frac.__index = Frac
local function gcd(a,b) return b==0 and a or gcd(b,a%b) end
function Frac.new(n,d)
local g = gcd(math.abs(n), math.abs(d))
return setmetatable({n=n//g, d=d//g}, Frac)
end
Frac.__tostring = function(f)
if f.d==1 then return tostring(f.n) end
return f.n .. "/" .. f.d
end
Frac.__add = function(a,b)
return Frac.new(a.n*b.d + b.n*a.d, a.d*b.d)
end
local a = Frac.new(1,2)
local b = Frac.new(1,3)
print(a + b) -- 5/6تجاوز سلوك print الافتراضي
تستدعي Lua الدالة print الدالة tostring لكل معامل، مع الفصل بينها بعلامات تبويب. وعند تعريف __tostring، ستُعرض كائناتك بصورة مفيدة في أي تعليمة طباعة أو رسالة خطأ أو استيفاء سلسلة نصية يستخدم tostring.
local Color = {}
Color.__index = Color
Color.__tostring = function(c)
return string.format("#%02X%02X%02X", c.r, c.g, c.b)
end
function Color.new(r,g,b)
return setmetatable({r=r,g=g,b=b}, Color)
end
local red = Color.new(255,0,0)
local green = Color.new(0,255,0)
local blue = Color.new(0,0,255)
print(red, green, blue)
-- #FF0000 #00FF00 #0000FF__name في Lua 5.3 والإصدارات الأحدث
تدعم Lua 5.3 والإصدارات الأحدث حقل __name في جدول الميتا، ويُستخدم في رسائل الخطأ الافتراضية لتحديد النوع. وعلى الرغم من أنه لا يؤثر مباشرةً في tostring()، فإنه يظهر في رسائل أخطاء وقت التشغيل عند إجراء عمليات غير صالحة على النوع.
local MyType = {}
MyType.__index = MyType
MyType.__name = "MyType" -- used in error messages
MyType.__tostring = function(t)
return "MyType(" .. tostring(t.value) .. ")"
end
local obj = setmetatable({value=42}, MyType)
print(obj) -- MyType(42)
-- Error message will say "MyType" instead of "table"
-- pcall(function() local x = obj + 1 end)تحقق سريع
متى تُستدعى __tostring؟
مراجعة: __tostring و__len
الملخص:
__tostring: تستدعيهاtostring()وprint()__len: يُستدعى بواسطة#obj؛ ويوفر طولًا موثوقًا للحاويات المخصصة- عرّف
__tostringفي جداول الفئات لجميع المثيلات - استخدم
__lenعندما لا تمنح بنية الجدول الخام قيمة صحيحة للعامل# - يسمّي
__name(في 5.3 والإصدارات الأحدث) النوع في رسائل الخطأ
الأسئلة الشائعة
هل درس «__tostring و__len» مجاني؟
نعم — نص درس «__tostring و__len» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.
ماذا ستتعلم في «__tostring و__len»؟
تحكّم في التمثيل النصي ومعامل # عبر الطرق الوصفية تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟
لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «__tostring و__len»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟
نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.