Menu
CoddyTech

نمط الـ Iterator

جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy. الدرس 64 من 70.

عندما يكون لديك مجموعة من العناصر مخزنة داخل كائن، غالبًا ما تريد المرور عليها باستخدام حلقة. تعمل حلقة for العامة في Lua مع أي دالة مُكرِّر: فهي تستدعي الدالة قبل كل تكرار، وتتوقف عندما تُرجع الدالة nil.

يمنح نمط المكرّر الكائنَ دالةً تُرجع مثل هذه الدالة. تحتفظ الدالة بموضعها في متغير محلي، لذا ينتمي الموضع إلى حلقة واحدة، لا إلى المجموعة:

local Collection = {}
Collection.__index = Collection

function Collection:new()
    local obj = { items = {} }
    setmetatable(obj, Collection)
    return obj
end

function Collection:add(item)
    table.insert(self.items, item)
end

function Collection:iter()
    local index = 0
    return function()
        index = index + 1
        return self.items[index]
    end
end

ينشئ كل استدعاء لـ bag:iter() دالة جديدة لها index خاص بها، وتبدأ قيمته من 0. الدالة إغلاق (closure): إذ لا يزال بإمكانها استخدام index وself بعد أن يعيد iter القيمة. بعد العنصر الأخير، تكون قيمة self.items[index] هي nil، وتتوقف الحلقة:

local bag = Collection:new()
bag:add("apple")
bag:add("banana")

for item in bag:iter() do
    print(item)  -- apple، ثم banana
end

for item in bag:iter() do
    print(item)  -- apple، ثم banana مرة أخرى
end

أبقِ الموضع خارج المجموعة نفسها. إذا خزّن الكائن self.index وعمل كمكرّر خاص به، فستنتهي الحلقة الأولى والمؤشر عند النهاية، لذا لن تطبع الحلقة الثانية شيئًا، كما أن الحلقة التي تتوقف مبكرًا باستخدام break ستجعل الحلقة التالية تبدأ من المنتصف.

challenge icon

التحدي

سهل

لننشئ صنف Playlist يمكنك التكرار عليه باستخدام حلقة for العامة في Lua! ستنفّذ نمط المكرّر باستخدام طريقة :iter() التي تُعيد دالة مكرّر.

ستوزّع شيفرتك على ملفين:

  • Playlist.lua: أنشئ صنف Playlist يخزّن الأغاني داخليًا. يحتاج صنفك إلى مُنشئ :new() يهيّئ قائمة أغاني فارغة، وإلى طريقة :addSong(title) تضيف أغنية إليها. والأهم من ذلك، أضف طريقة :iter() تُعيد دالة جديدة في كل مرة تُستدعى فيها. تحتفظ تلك الدالة بموضعها في متغيّر محلي، وتُعيد الأغنية التالية عند كل استدعاء، أو nil عندما لا تبقى أغانٍ.
  • main.lua: استورِد وحدة Playlist وأنشئ قائمة تشغيل جديدة. أضف إليها الأغاني استنادًا إلى المدخلات التي تتلقاها، ثم استخدم حلقة for عامة على playlist:iter() لطباعة عنوان كل أغنية في سطر مستقل.

لأن كل استدعاء لـ :iter() يبدأ من الأغنية الأولى، يمكنك تكرار قائمة التشغيل نفسها أي عدد من المرات.

ستتلقى ثلاثة مدخلات، يمثّل كل منها عنوان أغنية لإضافتها إلى قائمة التشغيل (بالترتيب).

على سبيل المثال، إذا كانت المدخلات هي Bohemian Rhapsody وStairway to Heaven وHotel California، فينبغي أن يكون الناتج:

Bohemian Rhapsody
Stairway to Heaven
Hotel California

إذا كانت المدخلات هي Yesterday وImagine وLet It Be، فينبغي أن يكون الناتج:

Yesterday
Imagine
Let It Be

جرّب بنفسك

-- استورد وحدة Playlist
local Playlist = require('Playlist')

-- اقرأ عناوين ثلاث أغانٍ من الإدخال
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()

-- TODO: أنشئ قائمة تشغيل جديدة باستخدام Playlist:new()

-- TODO: أضف الأغاني الثلاث إلى قائمة التشغيل باستخدام :addSong()

-- TODO: استخدم حلقة for عامة للتكرار عبر playlist:iter()
-- واطبع عنوان كل أغنية في سطر مستقل
-- تلميح: for song in playlist:iter() do ... end
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Lua عبر الإنترنت