فرا آرایه (MetaTable) :
اول جا تشکر ویژه داره که از گلپسر اشکان کنم که واقعا تو آموزشش بهم کمک کرد
اونی که تو صفحات قبل گفته شد به عنوان فرا آرایه ، فرا آرایه نبود (تا امروز فک میکردم بود) . آرایه ی چند بعدی بود (من فک میکردم هر دو یکی ان . دست اوستا امیر درد نکنه که منو متوجه کرد) بدش بگم که این چیزایی که گفته میشه ، تجربه ی من و راهنمایی اوستا اشکان هه . چون تجربه ام زیاد نیست ، ممکنه جاهایی درست مطلب گفته و جا نندازم یا حتی اشکال یا غلط بگم . هر کی که به درک کامل تر رسید ، اینجا تو این تاپیک کاملش کنه این مبحث رو
فرا آرایه در واقع یه آرایه ای هست که با توابعی که از پیش تعریف شده برای لوا هست (که دو تا علامت آندرلاین __ کنار اسم تابع اش داره) ، 2 کار رو تو آرایه ها انجام میده :
1) اگه مقدار یا عضوی از یه آرایه ای رو فراخونی کردیم که مقدارش nil بود ، با فرا آرایه میتونیم اون مقدار رو براش تعریف کنیم که دیگه nil نباشه و مقدار داشته باشه
2) عملگر و یا نوع فراخونی و بقیه ی کارای یک یا دو آرایه رو براش تعریف کنیم . ینی مثلا بصورت عادی نمیشه دو آرایه رو با هم جمع کرد اما با این حالت میشه
اگه این دو حالت پیش بیاد ، ینی مثلا یه عضوی از آرایه ای رو بخونیم که nil باشه و براش هم فرا آرایه ست کرده بودیم قبلا ،اون عضو از آرایه بجا اینکه nil رو برگردونه ، آرایه و الگوریتم فراآرایه رو اجرا میکنه
پس فراآرایه در واقع یه جوارایی ساختش ، به ماژول ها شباهت داره (آرایه ای که داخلش تابع تعریف میشه) . این توابع هم این طور نیست که آرگومان و ورودی هاش هر چی دلمون بخاد باشه چون این توابع تو لوا تعریف شده هست و باید با همون تداد آرگومانی این توابع رو بسازیم که تو لوا تعریف شد. لیست این توابع و عملکرداشونو میتونین بصورت کامل تو جدول قسمت پایین این صفه ببینین .(البته همونطور که گفته شد ، چون این توابع ها از پیش تعریف شده ان و تعداد و نوع آرگومان و ورودی هاشون باید همون جوری باشه که تعریف شد و تو اون لیست ، این ویژگی هاش و راهنماش نیومد ، فقط باید از مثال هاش پی ببرین و بازم چون همه ی توابع رو تو اون لینک مثال نزد ، شما میتونین با نوشتن اسم تابع و تو ادامه function example in lua ، تو سایتا سرچ کنین )
فرا آرایه هم با با تابع setmetatable برا یه آرایه تعریف میشه. این تابع ، دو آرگومان داره که تو آرگومان اولش آرایه ای که میخاین فرا آرایه براش ست کنین و نسبت بدین رو مینویسین و آرگومان دوم هم فراآرایه (که معلومه و گفته شد از نوع آرایه هست) رو مینویسین
تا اینجا دید یو آندرستود؟ ندید یو ؟ ببینین یو
بوریم مثالِ سر وقت (بریم سر وقت مثالا . مازندرانی رو باید یاد بگیرینا . از انگلیسی هم واجب تره ) :
نگا کنین در واقع تابع setmetatable دو کار میکنه . اول اینکه برا آرایه ، فرا آرایه ست میکنه و دوم اینکه مقدار آرایه ی داده شده (که تو آرگومان اول اش میدادیم) رو برمیگردونه . مثلا تو مثال زیر :
کد:
mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)
با این مثال :
کد:
mytable = setmetatable({},{})
هیچ فرقی نداره
تو مثال اول ، آرایه ای به عنوان آرایه ی اصلی که که فرا آرایه براش میخاد تعریف شه ، بنام mytable تعریف شد و بدش یه آرایه بنام mymetatable که به عنوان فرا آرایه ای که برا mytable میخاد ست شه و خط بدشو که توضیح دادم.
تو مثال دوم که همونطور که گفته شد ، تابع setmetatable ، آرایه ای که تو پارامتر اولش تعریف شد رو برمیگردونه پس mytable = {} میشه و علاوه بر اینکه فرا آرایه (پارامتر دوم) هم برا این آرایه ست میشه
تا اینجا مثال کلی بود . حالا بریم سراغ یه مثال واقعی :
تابع index__ :
یکی از مهمترین تابع برا ایجاد فرا آرای هست . کارش تعریف فراآرایه ای هست که اگه تو یه آرایه ، موقه فراخونی عضوی از اون آرایه ، اون عضوش nil باشه یا تعریف نشده باشه ، دیگه بجا برگردوندن nil ، اون فراآرایه اجرا میشه .
یه مثال :
کد:
mytable = setmetatable({key1 = "value1"}, {
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return mytable[key]
end
end
})
Dialog.Message("Notice", mytable.key1.."\n"..mytable.key2, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
اولا تو خط اول گفتیم که تابع setmetatable ، اولین پارامتر یا ورودی اش که آرایه هست رو برمیگردونه پس mytable یه آرایه هست اونم مقادیر و عضوهاش میشن :
کد:
mytable = {key1 = "value1"}
دوم اینکه میریم تو خط آخر . خط آخر ، میگه که key1 امین عضو از آرایه ی mytable رو فراخونی کن که خوب تعریف شده هست و مقدارشم برابر رشته ی value1 هه که موردی نداره و در ادامه ی Dialog.Message میگه Key2 امین عضو از آرایه ی mytable رو فراخونی کن . Key2 امین عضو از آرایه ی mytable وجود دارد عایا؟ ندارد عایا . پس چه میشود عایا؟ چون مقدارش برابر nil هه پس فرا آرایه ینی پارامتر دوم setmetatable اجرا میشه.
قبل از ادامه ، اول بزارین نحوه ی تعریف و اصول اولیه ی فرا آرایه گفته شه :
1) همونطور که گفته شد ، برا تعریف تابع ی فراآرایه ، از توابع از پیش تعریف شده ی لوا استفاده میشه (مثل index__ در این مثال و چن تا مثال دیگه در ادامه گفته میشه) که برا استفاده از راهنماش گفته شد
2) تعداد و نوع آرگومان و حتی اسم این توابع دست ما نیست و بازم باید از توی مثال های راهنمای انگلیسی متوجه شین (من انگلیسی ام عالیه ) و اغلب آرگومان هاشم راحت میشه حدس زد (تجربه ای متفاوت از حس شیشم) و اغلب تعداد آرگوماناش به تعداد آرایه ی استفاده و درگیر شده هست که اغلب 2 تاست و اغلب هم نوع آرگومان های این توابع هم از نوع آرایه هست و تو اغلب موارد هم آرگومان اول ، اون آرایه ی اصلی مونه که میخایم تغییرات روش انجام بشه
3) برا تعریف تابع تو فراآرایه ها ، مثل مثال بالا عمل کنین ینی اسم تابع مورد نظرتونو برابر بگیرین با کلمه ی فانکشن و بد براش آرگومان تعریف کنین . به این حالت تعریف کنین ، نمیشه ها چون علامت آندرلاین داره و ارور میده :
کد:
function __index(mytable, key)
اغلب در اغلب شد خو بَیته مِرِه شام زیاد خوردما ، شکمم پره ، خابم میاد. جاتون پر ، ماکارونی داشتیم
حالا بریم ادامه ی بحث درباره ی آرگومان دوم مثال بالا یا همون فراآرایه اش :
خوب تو این تابع index__ آرگومان هاش این جوریه که (گفته شد که نوع آرگمان اش رو باید تو مثال ها ببینین که از پیش تعریف شده هست و به احتمال بسیار زیاد قابل تغییر نیست) ، وقتی اسم و عضو آرایه فراخونی میشه ، قسمت اسم آرایه ، به یه پارامتر و قسمت عضو آرایه ، به یه پارامتر دیگه تو تابع مورد نظر (در اینجا تابع index__) ارسال میشه . الان تو قسمت Dialog.Message که mytable.key2 فراخونی شد ، اسم آرایه که mytable هه به پارامتر اول تابع index__ که از نوع آرایه هست ارسال شد و اسم key2 به پارامتر دوم این تابع که این بار از نوع رشته هست (ینی key2 بصورت رشته) وارد اونجا میشه که این نوع اش رو که تو اینجا تو این پارامتر ، رشته هست که گفته شد از پیش تعریف شده هست رو تو مثال ها میتونین پیدا کنین
ینی الان تو تابع index__ هر جا mytable نام برده شد ، همون آرایه mytable و هر جا key برده شد ، همون رشته ی "key2" هه منظورش (پس ورودی اول این تابع از نوع آرایه و ورودی دومش از نوع رشته هست)
بقیه دَوِّه فِردا . مِه چِش کور بَیِّه
خا کجا بودیم؟ آها رو کره ی زمین بودیم بریم ادامه مبحث
خوب چون تو mytable.key2 مقدار پارامتر key رشته هه و برابر key2 ینی :
هست ، و تو شرط تابع index__ این شرط گزاشته شده ، پس تابعش مقدار رشته ای metatablevalue رو برمیگردونه ینی بجا mytable.key2 ، رشته ی metatablevalue برگردونده و چاپ میشه تو Dialog.Message
راستی بجا نوع نگارش تابع تو خط بالا (الگوریتم تابع نه ها) میشه این طور هم نوشت اما من با روش بالا راحت ترم :
کد:
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
Dialog.Message("Notice", mytable.key1.."\n"..mytable.key2, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
حالا بریم سر وقت مثال دوم از نوع دوم که تعریف عملگر و فراخونی و ... بین دو آرایه بود بود.
اول تعریف عملگر بین دو آرایه :
کد:
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
for i = 1, table.maxn(newtable) do
table.insert(mytable, table.maxn(mytable)+1,newtable[i])
end
return mytable
end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
for k,v in ipairs(mytable) do
Dialog.Message("Notice", k.."\n"..v, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
end
تو توضیحش اینکه اولا تابع add__ دو تا آرگومان داره که اولیش آرایه اول ارسال میشه (قبل علامت جمع یا +) و برا دومیش آرایه ی دوم ارسال میشه (بعد علامت جمع در آرایه ها) و همونطور که از مثال هم معلومه ، تابع اولی که mytable هست و تو خط اول که پارامتر اول setmetatable هست ، تعریف شد، به عنوان پارامتر اول ، به تابع add__ فرستاده میشه و بعد علامت به علاوه که آرایه دوم و secandtable هست ، به عنوان پارامتر دوم به این تابع ارسال میشه
خوب حالا تو خط دهم ینی mytable = mytable + secondtable که مثل مثال قبل نیست که مقدار یه آرایه nil باشه و فراآرایه جاش اجرا بشه. پس چجوریه که با اجرای این خط فراآرایه اجرا میشه؟ فراآرایه ای که برا یه آرایه ست شد ، هر بار که اسم اون آرایه برده شد ، چک میکنه ببینه فراآرایه ای مناسب با عملی که براش تعریف کردیم ، تعریف شد یا نه . اگه تعریف شده بود فقط اجراش میکنه . ینی الان تو مثال بالا ، اگه یه آرایه ای رو فراخونی کنین که مقدارش nil باشه ، ارور میده چون فراآرایه ای که براش تعریف شد بخاطر اینکه تابع مورد نظر (index__) رو نداره ، اصلا اجرا نمیشه در این حالت
خوب حالا با اجرا شدن خط دهم ینی mytable = mytable + secondtable پارامترهای ارسالی که گفته شد و فراآرایه اجرا میشه . تو خط سوم :
کد:
for i = 1, table.maxn(newtable) do
table.insert(mytable, table.maxn(mytable)+1,newtable[i])
end
تابع table.maxn(newtable) ، با گرفتن اسم آرایه ، تعداد عضو هاش رو برمیگردونه که همون کار علامت # رو میکنه . ینی میتونین بجا خطوط بالا بنویسین :
کد:
for i = 1, #newtable do
table.insert(mytable, #mytable+1,newtable[i])
end
و دیگه ملومه که عضوهای آرایه ی newtable رو به عضوهای آرایه mytable اضافه میکنه . سر آخر هم همین آرایه ی mytable رو این تابع برمیگردونه (تو خطوط بالا) و بهتر ازم میدونین که ینی بجا mytable (سمت چپ تساوی خط دهم) ، مقدار mytable برگردونده میشه که شامل عضوهای اضافه شده ی آرایه ی newtable به آرایه ی خودشه ینی این :
کد:
mytable = { 1, 2, 3 ,4,5,6}
حالا مثال بدی (فراخونی آرایه . میدونین دیگه منظور همون تغییر عملکرد در فراخونی یا در واقع ست کردن فراآرایه ای برا فراخونی یه آرایه هست) :
کد:
mytable = setmetatable({10}, {
__call = function(mytable, newtable)
sum = 0
for i = 1, #mytable do
sum = sum + mytable[i]
end
for i = 1, #newtable do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {10,20,30}
Dialog.Message("Notice", mytable(newtable), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
برا فراخونی (ینی تغییر عملکرد و رفتار فراخونی یه آرایه یا در واقع ست کردن فراآرایه برا تغییر نوع فراخونی) از تابع call__ استفاده میکنیم
خوب همونطور که میدونین این فراآرایه تو مثال بالا ، موقعی اجرا میشه که خط آخر اجرا بشه ینی وقتی که تو پارامتر دوم گفتیم mytable(newtable)
دیگه ورودی این تابع call__ و الگوریتم هایی که توش بکار رفت کاملا مشخصه دیگه
مقدار بازگشتی شم تو این مثال 70 هه
تابع دیگه هم tostring__ هه که برا تغییر عملکرد فراخونی هه که تو مثال سایت بالا اومد
راستی این مثالا از همون لینکی که تو بالا داده شد گرفته شد (از گلپسر سید هم بخاطر معرفی این سایت ممنونم)
امیدوارم براتون مفید بوده باشه این آموزش
بازم دسِّت درد نکنه اوستا اشکان
علاقه مندی ها (بوک مارک ها)