فیلم آموزش کامل 8 Autoplay Media Studio + آموزشهای تکمیلی

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نکاتی درباره توابع در لوا :

1) تابع با چندین مقدار بازگشتی :

یک تابع میتواند چندین مقدار بازگشتی را بازگرداند. در این صورت باید به تعداد مقدار بازگشتی آن تابع (مثلا فرض میکنیم تابع مان 3 مقدار بازگشتی دارد)، برایش متغییر تعریف کرد و همه ی متغییرها را با ویرگول از هم جدا کرد . مثلا در مثال زیر :

کد:
[FONT=tahoma]function func(a,b)[/FONT]
[FONT=tahoma]Val1 = a+b[/FONT]
[FONT=tahoma]Val2=a*b[/FONT]
[FONT=tahoma]Val3 = a-b[/FONT]
[FONT=tahoma]return Val1,Val2,Val3[/FONT]
[FONT=tahoma]end[/FONT]


[FONT=tahoma]Plus,multiplication,Minus = func(200,100)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "a+b = "..Plus.."\na*b = "..multiplication.."\na-b = "..Minus, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

تابع بالا که اسمش func هست ، 3 مقدار Val1 و Val2 و Val3 را برمیگرداند . موقع فراخوانی ، هر کدام به ترتیب داخل متغییرهای مربوط به خودشان (که موقع فراخوانی تابع func از آن استفاده کردیم) ذخیره میشوند. یعنی مقدار بازگشتی Val1 (که در مثال بالا مقدارش 300 هست) داخل متغییر Plus و مقدار Val2 (که مقدارش 20000 هست) داخل متغییر multiplication و مقدار Val3 (که مقدارش 100 هست) داخل متغییر Minus ذخیره میشوند
یعنی اولین مقدار بازگشتی ، داخل الین متغییر و دومین مقدار بازگشتی داخل دومین متغییر و ... ذخیره شده است
توجه کنید که اگر مثلا در فراخوانی تابعی که 3 مقدار بازگشتی دارد ، فقط 2 متغییر به آن تابع اختصاص دهیم ، در واقع دو مقدار بازگشتی را فقط به آن تابع اختصاص دادیم و مقدار بازگشتی سوم ، بلا استفاده میماند . یا مثلا اگر این تابع را بدون اختصاص دادن متغییر فراخوانی کردیم ، فقط مقدار بازگشتی اول را برمیگرداند یعنی در مثال بالا اگر این طور بنویسیم:

کد:
[FONT=tahoma]function func(a,b)[/FONT]
[FONT=tahoma]Val1 = a+b[/FONT]
[FONT=tahoma]Val2=a*b[/FONT]
[FONT=tahoma]Val3 = a-b[/FONT]
[FONT=tahoma]return Val1,Val2,Val3[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]Dialog.Message("Notice", func(200,100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

تابع func ، فقط مقدار اول که Val1 بود (که مقدارش 300 میشد) را برمیگرداند

2) اجرای تابع داخل آرگومان:
اگر در تابعی ، تابع دیگری فراخوانی شود به عنوان آرگومان ، معلوم هست که اول تابع داخلی (تابعی که در آرگومان آن تابع فراخوانی شد) اجرا و مقدار بازگشتی اش (اگر داشت . در این مثالزیر ، مقدار بازگشتی اش ، عدد هست) به عنوان آرگومان تابعی که در آن فراخوانی شد ، ارسال میشود:

کد:
[FONT=tahoma]Dialog.Message("Notice", Dialog.Message("Notice", "Your message here.", MB_YESNO, MB_ICONINFORMATION, MB_DEFBUTTON1), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

در مثال بالا ، اول تابعی که در آرگومان دوم تابع اولیه فراخوانی شد ، اجرا و مقدار بازگشتی اش به عنوان آرگومان دوم ، ارسال میشود
یا مثل مثال زیر :

کد:
[FONT=tahoma]function first(arg1)[/FONT]
[FONT=tahoma]arg1=arg1^2[/FONT]
[FONT=tahoma]return arg1[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]function secand(arg2,arg3)[/FONT]
[FONT=tahoma]new=arg2/arg3[/FONT]
[FONT=tahoma]return new[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]NewNum = secand(first(6),9)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", NewNum, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]


3) اجرای تابع داخل تابع دیگر :
هر وقت تابعی داخل تابع دیگر باشد ، تابع داخلی آن ، مثل توابع دیگر تا از تابع خارجی آن فراخوانی نشود ، اجرا نمیشود . مثل :

کد:
[FONT=tahoma]function Init(a,b,c)[/FONT]
[FONT=tahoma]function Sec(a,b)[/FONT]
[FONT=tahoma]ABC = a+b+5[/FONT]
[FONT=tahoma]return ABC[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]return Sec(a,b)[/FONT]
[FONT=tahoma]end[/FONT]


[FONT=tahoma]Nm = Init(10,20,30)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", Nm, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

در مثال بالا ، تا زمانی که تابع داخلی آن (تابع Sec) از تابع خارجی آن (تابع Init) فراخوانی نشود ، تابع Sec اجرا نمیشود .
باید توجه داشت که بصورت مستقیم نمیتوانیم تابع داخلی یک تابع را فراخوانی کنیم چون تابع اجرا نشده و تا تابعی اجرا نشود (و کلا هر مقداری در لوا تعریف نشود) ، مقدارش nil است یعنی در مثال بالا نمی توانیم این جوری فراخوانیکنیم :

کد:
[FONT=tahoma]function Init(a,b,c)[/FONT]
[FONT=tahoma]function Sec(a,b)[/FONT]
[FONT=tahoma]ABC = a+b+5[/FONT]
[FONT=tahoma]return ABC[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]return Sec(a,b)[/FONT]
[FONT=tahoma]end[/FONT]


[FONT=tahoma]Nm = Sec(10,20)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", Nm, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

4) بدست آوردن تعداد مقادیر بازگشتی یک تابع (select) :
برای درک تعداد مقادیر بازگشتی یک تابع ، میتوانید از تابع select (تابع اصلی لوا) کمک بگیرید
اولین آرگومان (ورودی) این تابع شماره ی متغییر (آرگومان) ای را میدهیم که در آرگومانهای بعدی این تابع نوشتیم . مثلا در مثال زیر :

کد:
[FONT=tahoma]value = select(2,"hello","word",67,"string",87)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", value, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

چون در آرگومان اول ، عدد 2 آورده شد ، یعنی دومین آرگومان بعد از خودش (به غیر از خودش) را برگردان (یعنی سومین آرگومان) که میشود رشته ی word
در مثال زیر :

کد:
[FONT=tahoma]function func(first,secand)[/FONT]
[FONT=tahoma]first=first+1[/FONT]
[FONT=tahoma]secand=secand-1[/FONT]
[FONT=tahoma]return first,secand[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]Dialog.Message("Notice", select(2,func(5,2)), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

چون تابع func ، دو مقدار را برمیگرداند ، پس 2 مقدار در دو آرگومان تابع select ذخیره میشود (اولیین آرگومان تابع select که عدد 2 هست و دومین آرگومان که همان اولین مقدار بازگشتی تابع func (مقدار first) و سومین آرگومان هم برابر دومین مقدار بازگشتی تابع func (مقدار secand) است) پس معلوم است که خروجی تابع select ، یکی بعد از اولین آرگومان(که 2 است) یعنی سومین آرگومان تابع select که مقدار secand (که مقدارش 1 هست) میباشد
مثال بالا برابر است با مثال زیر :

کد:
[FONT=tahoma]function func(first,secand)[/FONT]
[FONT=tahoma]first=first+1[/FONT]
[FONT=tahoma]secand=secand-1[/FONT]
[FONT=tahoma]return first,secand[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]One,Two = func(5,2)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", select(2,One,Two), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

اگر بجای اولین تابع select ، بجای شماره (عدد) ، رشته ی "#" را قرار دهیم ، تعداد آرگومان هایی که در آن وجود دارد را باز میگرداند . پس برای بدست آوردن تعداد مقادیر بازگشتی یک تابع ، کافیست در اولین آرگومان تابع select ، رشته ی "#" و در دومین آرگومانش ، تابع مورد نظر را فراخوانی کنیم . پس برای بدیت آوردن تعداد بازگشتی تابع func در مثال اول ، کافیست :

کد:
[FONT=tahoma]function func(a,b)[/FONT]
[FONT=tahoma]Val1 = a+b[/FONT]
[FONT=tahoma]Val2=a*b[/FONT]
[FONT=tahoma]Val3 = a-b[/FONT]
[FONT=tahoma]return Val1,Val2,Val3[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]Dialog.Message("Notice", select("#",func(5,2)), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

نکته : برای متوجه شدن تعداد مقادیر بازگشتی یک تابع ، از این روش استفاده میکنیم ولی برای متوجه شدن تعداد یک آرایه این تابع کارایی ندارد . برای این منظور کافیست علامت # (دقت کنید که این بار رشته نیست) را کنار اسم آرایه بگذارید (اما دقت کنید که این روش برای آرایه ها،در مواردی که عضو آرایه ها بصورت عدد نباشند (بصورت index نباشند) و با حروف تعریف شوند ، جواب نمیدهد که در این صورت باید از تابع Table.Count از AMS استفاده کنید وگرنه در لوا باید از تابع pairs در iterator ها (در مقاله های بعد ، آموزش ایتریتورها گفته خواهد شد) ، استفاده کنید)


5) استفاده از علامت آندرلاین _ برای متغییرهای بلا استفاده :
گاهی داخل بعضی از الگوریتم ها ، برای توابعی که چندین مقدار بازگشتی دارند ، از علامت آندرلاین _ برای آن متغییر استفاده میشود (یا با همان تابع select میتوان بهتر مدیریت کرد) . هر چند این متغییر هم مثل متغییرهای عادی قابل استفاده هست و فرقی ندارد که بجای آن ، از اسمی دیگر استفاده کرد :

کد:
[FONT=tahoma]_,s = string.find("This is Lua in", "Lua")[/FONT]
[FONT=tahoma]Dialog.Message("Notice", s, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

که در اینجا متغییر اول تابع string.find ، که با _ مشخص شد ، استفاده نمیکنند (البته میشود استفاده هم کرد مثل بقیه ی متغییرها)


6) تابع با ورودی و آرگومان متفاوت :
برای تعریف تابع (و هر آرگومان دیگر) که تعداد آرگومان هایش از قبل مشخص نباشند ، از علامت سه تا نقطه ... استفاده میشود . بعد ورودی ها را داخل آرایه میریزیم و بعد با بدست آوردن تعداد آن (که با علامت # مشخص میشد) ، به الگوریتم مان میپردازیم :

کد:
[FONT=tahoma]function average(...)[/FONT]
[FONT=tahoma]result = 0[/FONT]
[FONT=tahoma]local arg={...}[/FONT]
[FONT=tahoma]for i,v in pairs(arg) do[/FONT]
[FONT=tahoma]result = result + v[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]return result/#arg[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]برای فراخوانی و استفاده هم :[/FONT]
[FONT=tahoma]Debug.Print(average(1,4,3,5,4).."\r\n"); --result = 3.5[/FONT]
[FONT=tahoma]Debug.Print(average(1,4,5,4,4,3,7,8,9,4,2,9).."\r\n"); --result = 5[/FONT]
[FONT=tahoma]Debug.Print(average(2,9)); --result = 5.5[/FONT]
[FONT=tahoma]Debug.ShowWindow(true);[/FONT]

7) تابع بی نام :
این نوع تابع که اسم ندارد ، اغلب زمانی به کار میاید که بعد از تعریف ، فورا اجرایش کنیم . البته به ندرت این نوع توابع رو در مثال ها میبینیم.
ساختارش هم مثل تابع معمولی است و فقط اسم ندارد به اضافه ی اینکه قبل تعریف تابع ، یک پرانتز باز میکنیم و بعد آن پرانتز را میبندیم و بلافاصله بعدش مثل اجرای همه ی توابع که نشانه ی شان (بعد از فراخوانی اسم تابع که آرگومان ها را مینویسیم) دو پرانتز است ، دو پرانتز را باز و میبندیم که نشانه ی اجرای تابع تعریف شده باشد .
ساختارش به شکل زیر است :

کد:
[FONT=tahoma](function ()[/FONT]

[FONT=tahoma]end)()[/FONT]
[FONT=tahoma]مثلا :[/FONT]
[FONT=tahoma](function (a,b)[/FONT]
[FONT=tahoma]a=a*a[/FONT]
[FONT=tahoma]Dialog.Message("Notice", a, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end)(6,7)[/FONT]


8) تبدیل رشته به تابع (loadstring) :
تابع loadstring که جزء توابع اصلی لواست ، رشته را به عنوان ورودی دریافت و به تابع قابل اجرا تبدیل میکند (البته اگر رشته ها طبق قواعد لوا یا AMS تعریف شده باشند)
چون مقدار بازگشتی اش تابع هست ، پس برای اجرای آن مثل همه ی توابع ، آخرش باید علامت تابع (که در نکته ی 7 گفته شد دو علامت پرانتز هست) گذاشته شود
نکته ی جالب توجه اینکه بعد از اجرای این تابع ، مقدار بازگشتی اش (مقدار بازگشتی loadstring بعد از اجرا) ، nil میشود
نکته ی بعد اینکه در لوا برای تعریف رشته هم از علامت " " و هم از علامت ' ' و هم از علامت [[ ]] استفاده میشود
در مثال زیر ، قبل از اجرا شدن تابع loadstring ، میتوانید نوع بازگشتی آنرا که تابع هست ، ببینید :

کد:
[FONT=tahoma]Qw=[[[/FONT]
[FONT=tahoma]a=5[/FONT]
[FONT=tahoma]c=a*4[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "in anonymous function!\n"..c, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]]][/FONT]

[FONT=tahoma]x=loadstring(Qw)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", type(x), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

در مثال زیر هم (که با گذاشتن علامت دو پرانتز ، آخر تابع loadstring به منظور اجرای تابع بازگشتی آن) ، رشته ی اصلی را اجرا کنید و بعد ، نوع بازگشتی را که قبلا اجرا function یا تابع بود و بعد از اجرا که nil میشود را ببینید :

کد:
[FONT=tahoma]Qw=[[[/FONT]
[FONT=tahoma]a=5[/FONT]
[FONT=tahoma]c=a*4[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "in anonymous function!\n"..c, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]]][/FONT]

[FONT=tahoma]x=loadstring(Qw)()[/FONT]
[FONT=tahoma]Dialog.Message("Notice", type(x), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]


9) استفاده از حلقه در تابع :
اگر در تابعی ، حلقه ای بکار رود که داخل آن حلقه ، مقدار بازگشتی (return) برای تابع لحاظ شود ، آن تابع دیگر تکرار نمیشود با آنکه حلقه ی تکرار در آن وجود دارد مثل :

کد:
[FONT=tahoma]function DontRept()[/FONT]
[FONT=tahoma]for i=1,5 do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", i, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]return i[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]DontRept()[/FONT]

اما اگر مقدار بازگشتی خارج از آن حلقه تعریف شود ، موردی ندارد و تابع تکرار میشود مثل :

کد:
[FONT=tahoma]function Rept()[/FONT]
[FONT=tahoma]for i=1,5 do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", i, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]return i[/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]Rept()[/FONT]

10) فراخوانی تابع با تک آرگومان آرایه ای :
اگر تابعی تعریف کنیم که فقط یک آرگومان آن هم از نوع آرایه داشته باشد (نه چندین آرگومان) ، میتوانیم علامت تابع یعنی پرانتز را هنگام فراخوانی نگذاریم یعنی :

کد:
[FONT=tahoma]function Ty(Arr1)[/FONT]
[FONT=tahoma]return Arr1[2][/FONT]
[FONT=tahoma]end[/FONT]

[FONT=tahoma]Dialog.Message("Notice", Ty{560,"salam"}, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

11) ایجاد و فراخوانی آرایه به روشی دیگر :
اگر آرایه ای داشته باشیم که key (یا به اصطلاح سمت چپ تساوی آن ، در متغییری ذخیره شده باشد) ، مثل متغییر foo و x و y در آرایه ی زیر :

کد:
[FONT=tahoma]t={foo="bar",x=5,y=true}[/FONT]

به 2 حالت میشود آنرا فراخوانی کرد که اول به این گونه:

کد:
[FONT=tahoma]t.foo[/FONT]
[FONT=tahoma]t.x[/FONT]
[FONT=tahoma]t.y[/FONT]

برابر است با نوع دوم اش به این گونه :

کد:
[FONT=tahoma]t["foo"][/FONT]
[FONT=tahoma]t["x"][/FONT]
[FONT=tahoma]t["y"][/FONT]

برای ایجاد آرایه هم میشود key ها را بصورت در هم شماره بندی و مقدار دهی کرد یعنی :

کد:
[FONT=tahoma]t={[3]=12,[7]="salam",[1]="word",[10]=653}[/FONT]
[FONT=tahoma]Dialog.Message("Notice", t[1].."\n"..t[3].."\n"..t[7].."\n"..t[10], MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]

که [1]t برابر رشته ی "word" و [3]t برابر 12 و [7]t برابر رشته ی "salam" و [10]t برابر 653 هست . توجه کنیم که در این حالت بقیه ی مقادیر nil هست مثل [2]t و ... و هم اینکه نباید در این حالت که همه ی key ها شماره گذاری شده اند ، بعضی از آنها را شماره گذاری نکنیم مثلا این طور صحیح نیست :

کد:
[FONT=tahoma]t={[3]=12,"salam",[1]="word",653[/FONT]
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
File I/O در لوا :

همونطور که مشخص است ، این عبارت ، مخفف File Input Output به معنای ورودی و خروجی فایل هست و توابع این بخش دست ما رو برای خواندن از یک فایل یا نوشتن روی آن باز میگذارد
اما قبل از پرداختن به موضوع File I/O ، درباره ی عملگر : (عملگر کلون یا colon) در لوا میپردازیم که یکی از کاربردهای آن در شی گرایی در لواست و یک بخش کوچچکی از شی گرایی در لوا را که به این عملگر مربوط است توضیح میدهیم :
به این کد دقت کنید :

[CODE]
Account = {balance = 0,x=3}


function Account.withdraw(v)
Account.balance = Account.balance - v
return Account.balance
end


a = Account;
Account = nil
Dialog.Message("Notice", a.withdraw(100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);

[/CODE]

اگر ساختار بالا برایتان گنگ هست ، پس حتما اول مبحث ماژول ها را مطالعه بفرمایید و بعد به این مبحث وارد شوید (چون تا آخر یکی از بحث ها همین ماژول و فراخوانی آن هست در File IO) ولی به اختصار ، ماژول ، به عضوی از آرایه که بصورت تابع یا متغییر تعریف میشود ، میگویند و فراخوانی آن با علامت دات (نقطه) ما بین اسم آرایه و اسم تابع یا متغییر هست. تابع بالا را هم به شکل زیر هم میشود نوشت و فرقی با هم ندارند :

[CODE]
Account = {balance = 0,x=3,withdraw=function (v)
Account.balance = Account.balance - v
return Account.balance
end}


a = Account;
Account = nil
Dialog.Message("Notice", a.withdraw(100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
[/CODE]

اگر در هر ماژولی ، نام آرایه ی اصلی آن (منظور عضوهای داخلی نیست. منظور در مثال بالا ، بصورت مستقیم ، آرایه ی Account است نه عضوهای آن) برابر پوچ یا nil قرار داده شود ، هر کجا برای فراخوانی ، نام آرایه ای که برابر nil قرار گرفت فراخوانی شود (در کد بالا همان نام آرایه ی Account) ، چون مقدارش پوچ است پس ارور میدهد و اعضای آن فراخوانی نمیشوند به این ترتیب ، در کد بالا :
اولا دیگر نمیشود عضوهای آن (متغییرهای balance و x) بصورت مستقیم در دسترس باشند مگر اینکه قبلا نام آن آرایه رو در متغییر دیگری ریخته باشیم . پس در کد بالا چون در خط 9 ، چون آرایه ی اصلی آنرا که Account بود را برابر nil گرفتیم بنابراین از آن خط به بعد هیچ گاه نمیتوانیم عضوهای آن آرایه را این گونه بصورت مستقیم فراخوانی کنیم و بنویسیم :

[CODE]
Account.x
Account.balance
Account.withdraw(100)
[/CODE]

چون این نوع فراخوانی مثل این است که آرایه ای را تعریف نکرده ، عضوهای آن را فراخوانی کنیم
و اگر در خط 8 ، آرایه ی Account را در متغییر دیگری نمیریختیم ، دیگر نمیشد از عضوهایش استفاده کرد و از این به بعد همانطور که مشخص هست ، باید اعضای این آرایه را بصورت غیر مستقیم فراخواند و چون آرایه ی Account را در متغییر a ریختیم ، از این به بعد عضوهای این آرایه بصورت غیر مستقیم فقط با فراخوانی متغییر a در دسترس اند یعنی باید این گونه فراخوانی کنیم :

[CODE]
a.x
a.balance
[/CODE]

خوب حالا موقع فراخوانی تابع میرسد . میبینیم که با فراخوانی :

[CODE]
a.withdraw(100)
[/CODE]

با وجود اینکه بصورت غیر مستقیم تابع مان فراخوانی شد ، باز هم ارور میدهد و تابع فراخوانی نمیشود . چرا؟
اگر نگاهی به بدنه ی تابع مان (منظور سر یا هدر تابع نیست) بیاندازید ، میبینید که در بدنه ی تابع ، آرایه ی Account فراخوانی شد و چون این مقدار را برابر nil کرده بودیم ، پس مشخص هست به این دلیل است که ارور میدهد همانطور که برای فراخوانی عضوهای قبلی این آرایه ، وقتی بصورت مستقیم فراخوانی میکردیم ، ارور میداد.
اما چاره چیست؟
در این گونه مواقع همانطور که قبلا بجای آرایه ی Account ، متغییری که آرایه ی Account را که در آن ریخته بودیم (متغییر a) را جایگزین اش میکردیم یک ورودی یا پارامتری برای این تابع ساخته و در بدنه ی این تابع هم مثل قبل ، جایگزین آن میکنیم (به هدر تابع که Account.withdraw هست فقط کاری نداریم) یعنی این گونه کد را اصلاح میکنیم :

[CODE]
Account = {balance = 0,x=3}


function Account.withdraw(ArrayPar,v)
ArrayPar.balance = ArrayPar.balance - v
return ArrayPar.balance
end


a = Account;
Account = nil
Dialog.Message("Notice", a.withdraw(a,100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
[/CODE]

یعنی چون در بدنه ی تابع مان Account آمد و این آرایه هم پوچ بود ، باید این Account را در بدنه ی اصلی تابع ، جایگزین میکردیم و دقیقا مثل قبل جایگزین آن متغییری که آن آرایه را در آن ذخیره کرده بودیم پس باید در فراخوانی، در پارامتر به عنوان ورودی ، مثل قبل ، همان متغییر a را که محتوای آرایه ی Account در آن ذخیره بود را بفرستیم تا بجای Account ، این پارامتر را جایگزین آن کنیم
پس در فراخوانی :

[CODE]
a.withdraw(a,100)
[/CODE]

بجای Account ، متغییر a را به عنوان اولین آرگومان که جایگزین اولین آرگومان تابع که ArrayPar هست ، فرستادیم برای آنکه در بدنه ی تابع اصلی ، آرایه ی Account بصورت مستقیم فراخوانی نشود
آرگومان ArrayPar در تابع بالا ، معروف به آرگومان self یا this هستند و مظهر و نشانه ی این هستند که بجای هر عضوی از آرایه یا حتی خود آرایه (مثل مثال بالا) که nil شد ، به عنوان پارامتر جایگزین در بدنه ی تابع ، مشکل اختلال تابع را حل کنند
خوب اما نقش عملگر کلون : (colon) چیست؟
هر گاه در تابعی به عنوان ماژول (تابع در آرایه) مثل کد بالا ، به هر دلیل (دلیل بالا ، nil شدن مقدار Account بود) نیاز شد که پارامتری را به عنوان نام آرایه (یا ماژول ...) را بصورت مخفیانه بفرستیم ، از علامت کلون یعنی این علامت : استفاده میکنیم. مثلا بجای فراخوانی تابع بصورت :

[CODE]
a.withdraw(a,100)
[/CODE]

به این صورت فراخوانی کنیم :

[CODE]
a:withdraw(100)
[/CODE]

یا بجای نوشتن هدر تابع (به هدر تابع دقت کنید نه به بدنه اش) ، به این صورت :

[CODE]
function Account.withdraw(ArrayPar,v)
ArrayPar.balance = ArrayPar.balance - v
return ArrayPar.balance
end
[/CODE]

این گونه بنویسیم :

[CODE]
function Account:withdraw(v)
self.balance = self.balance - v
return self.balance
end
[/CODE]

یعنی کد بالا را میتوانیم به این صورت بنویسیم :

[CODE]
Account = {balance = 0,x=3}


function Account.withdraw(ArrayPar,v)
ArrayPar.balance = ArrayPar.balance - v
return ArrayPar.balance
end


a = Account;
Account = nil
Dialog.Message("Notice", a:withdraw(100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
[/CODE]

به فراخوانی تابع a:withdraw(100) در خط آخر دقت کنید که همان فرقی با فراخوانی a.withdraw(a,100) ندارد
به عبارتی دیگر هر گاه خواستیم سمت چپ عملگر : (که در فراخوانی بالا ، سمت چپ عملگر : همان متغییر a هست) را بصورت مخفیانه به عنوان پارامتر تابع بفرستیم ، از این عملگر استفاده میکنیم یعنی هر کجا که علامت کلون استفاده شد در پارامتر آن ، آرایه یا متغییری که در کد بالا استفاده میکردیم ، حذف میکنیم .حالا نکته اینجاست که اگر در موقع فراخوانی تابع از علامت کلون استفاده کردیم فقط میتوانیم این پارامتر را از قسمت فراخوانی این تابع حذف کنیم و دیگر نباید این پارامتر را موقع هدر و تعریف تابع حذف کرد . یعنی :

[CODE]
Account = {balance = 0,x=3}


function Account.withdraw(ArrayPar,v)
ArrayPar.balance = ArrayPar.balance - v
return ArrayPar.balance
end


a = Account;
Account = nil
Dialog.Message("Notice", a:withdraw(100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
[/CODE]

در کد بالا ، چون فقط در خط آخر یعنی موقع فراخوانی تابع ، از علامت کلون استفاده کردیم پس فقط میتوانیم از همین قسمت این پارامتر را که قبلا به عنوان پارامتر a جایگزین کرده بودیم ، حذف کنیم ولی در قسمت تعریف تابع چئت از این علامت استفاده نکردیم ، پس نباید این پارامتر را از آنجا حذف کنیم . عکس این گفته هم صادق است
نکته ی مهمی که در قضیه ی کلون است ، این است که همونطور که قبلا گفته شد ، این پارامتر فقط بنام self یا this فقط در تابع شناخته میشود البته در صورتی که مخفی باشد یعنی از علامت کلون استفاده شود پس اگر در تعریف تابع بالا یعنی Account.withdraw ، اگر از علامت کلون استفاده کردیم و مجبور شدیم که ArrayPar رو پاک کنیم از پارامترش ، حالا باید در بدنه ی تابع ، بجای متغییر ArrayPar از نام متغییر self (همه ی حروف ها کوچک) استفاده کنیم یعنی :

کد:
Account = {balance = 0,x=3}[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]function Account:withdraw(v)[/FONT]
[FONT=tahoma]self.balance = self.balance - v[/FONT]
[FONT=tahoma]return self.balance[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]a = Account[/FONT][FONT=tahoma];[/FONT]
[FONT=tahoma]Account = nil[/FONT]
[FONT=tahoma]Dialog.Message("Notice", a:withdraw(100), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1)[/FONT][FONT=tahoma];[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]حالا به مبحث اصلی مان که [/FONT][FONT=tahoma]File I/O[/FONT][FONT=tahoma] هست میپردازیم :[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]نکته ی بسیار مهمی که همان ابتدای کار باید بیان شود این است که برای استفاده (خواندن یا نوشتن) از یک فایل ، ابتدا باید آن فایل را برای قصد مورد نظر (منظور برای خواندن یا اینکه برای نوشتن است) باید باز شود و نکته ی مهم دیگر این است که وقتی کارمان تمام شد ، باید آن فایل را ببندیم. (منظور از باز کردن و بستن ، دابل کلیک روی فایل نیست . بلکه با توابع [/FONT][FONT=tahoma]file i/o[/FONT][FONT=tahoma] لوا باید این کار را انجام داد که در ادامه عرض میشود)[/FONT]
[FONT=tahoma]دقت کنید باز کردن یک فایل به معنای خواندن محتوای آن نیست . باز کردن فایل هم با تابع [/FONT][FONT=tahoma]io.open[/FONT][FONT=tahoma] در لوا انجام میگیرد . توضیحات این توابع بصورت انگلیسی در لینک زیر موجود است که در ادامه به بررسی مهم ترین این توابع میپردازیم :[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]http://www.lua.org/manual/5.1/manual.html#pdf-io.close[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]در فرآیند باز کردن یک فایل ،باید به این چند نکته هم توجه کرد :[/FONT]
[FONT=tahoma]اول و مهمترین آن اینکه میخواهیم محتوای فایل مورد نظر را بخوانیم یا بنویسیم . همانطور که گفته شد ، قبل از هر عملیات خواندن یا نوشتن ، ابتدا باید فایل را باز کرد اما نکته ی حائز اهمیت اینجاست که باز کردن فایل برای خواندن و باز کردن فایل برای نوشتن متفاوت است یعنی اگر قصد خواندن یک فایل را داریم ، قبل از خواندن ، باید فایل مورد نظر را برای خواندن باز کنیم و اگر قصد نوشتن آنرا داریم ، قبل از آن باید فایل را برای نوشتن باز کنیم . دقت کنیم که اگر قصد نوشتن فایل را داشته باشیم و قبل از آن ، فایل را برای خواندن باز کرده باشیم ، عملیات نوشتن روی آن فایل انجام نمیشود و برعکس اش هم صادق است[/FONT]
[FONT=tahoma]دوم آنکه موقع باز کردن فایل ، مشخص کنیم که آن فایل را برای حالت باینری میخواهیم باز کنیم (جهت خواندن یا نوشتن) و یا حالت متن معمولی . برای تشخیص اینکه یک فایلی به حالت باینری است یا متن معمولی ، آنرا با [/FONT][FONT=tahoma]notpad[/FONT][FONT=tahoma] باز کنید و اگر محتوای آن فقط و فقط حاوی متن قابل تشخیص بود ، بصورت متن عادی آن فایل ذخیره شده است و اگر غیر از این بود یعنی حاوی کاراکترهای ناشناخته و درهم بود ، (که معمولا غیر از فایل های [/FONT][FONT=tahoma]txt[/FONT][FONT=tahoma] ، بقیه این طور هستند) آن فایل بصورت باینری هست و برای باز کردن آن (جهت خواندن یا نوشتن آن فایل) صورت باینری باز شود. مشخص هست که اگر با توابع باینری لوا مثل تابع [/FONT][FONT=tahoma]string.dump[/FONT][FONT=tahoma] اگر کار میکنیم ، برای ذخیره کردن و نوشتن در داخل فایل ، باید آن فایل را بصورت باینری برای نوشتن باز کنیم[/FONT]
[FONT=tahoma]دقت کنید که عملیات باز کردن حتی برای فایلی که از قبل وجود ندارد و تازه میخواهیم آن فایل را بنویسیم و تولید کنیم هم باید انجام شود[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]در توابع [/FONT][FONT=tahoma]File I/O[/FONT][FONT=tahoma] ، دو دسته توابع وجود دارند که در واقع فرق شان در علامت کلون یا علامت : است . آن توابعی (در واقع ماژول) که بصورت عادی یا علامت دات (نقطه) دارند مثل [/FONT][FONT=tahoma]io.input[/FONT][FONT=tahoma] و ... ، معمولا مسیر فایل مورد نظر را بصورت پارامتر تابع دریافت میکنند مثلا در همین [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]io.input ([file])[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]هست که باید بجای آرگومان ورودی [/FONT][FONT=tahoma]file[/FONT][FONT=tahoma] ، مسیر کامل فایل را بدهیم[/FONT]
[FONT=tahoma]اما در توابعی که علامت کلون یا : را دارند ، همانطور که در بالا گفته شد ، هر گاه این علامت بیاید ، آرگومان خاص و از پیش تعیین شده ای را که در اینجا همان مسیر فایل بجای آرگومان [/FONT][FONT=tahoma]file[/FONT][FONT=tahoma] در بالاست ، از آرگومان ورودی این نوع توابع حذف میشوند و بجایش این پارامتر را (که مسیر فایل را مشخص میکرد) به عنوان هندل فایل (نه به عنوان رشته ای به عنوان مسیر فایل) قبل از علامت کلون یا : میگیرند . یعنی در تابعی مثل [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]file:read[/FONT][FONT=tahoma]()[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]متغییر [/FONT][FONT=tahoma]file[/FONT][FONT=tahoma] (که قبل از علامت کلون : آمده است) یک متغییریست که بجای رشته ی مسیر فایل (که به عنوان پارامتر ورودی تعریف میشد در توابع بدون کلون) ، هندل که شماره ای خاص از آن فایل است را میگیرد . هندل هم در ادامه بیشتر میپردازیم اما فعلا همین قدر کافی است که تابع [/FONT][FONT=tahoma]io.open[/FONT][FONT=tahoma] علاوه بر باز کردن (منظور خواندن و نوشتن نیست) فایل مورد نظر ، هندل آنرا برمیگرداند که میتوانیم از متغییری که از این تابع برگردانده میشود ، در تابعی با علامت کلون مثل [/FONT][FONT=tahoma]file:read[/FONT][FONT=tahoma] قبل از متغییر کلون که [/FONT][FONT=tahoma]file[/FONT][FONT=tahoma] بود ، بجایش استفاده کنیم [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]حالا به بررسی توابع [/FONT][FONT=tahoma]File I/O[/FONT][FONT=tahoma] بپردازیم :[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]همانطور که گفته شد ، توابع [/FONT][FONT=tahoma]file i/o[/FONT][FONT=tahoma] به دو دسته ی عملگر کلون دار و بدون کلون تقسیم میشوند اما توابع با کلون ، به مانند توابع بدون کلون ، کامل نیستند اما چون توابعی که علامت یا بهتر بگوییم عملگر کلون دارند ، فقط هندل فایل را میخواهند و مسیر فایل به عنوان آرگومان از آنها حذف شد ، پس کار کردن با آنها راحت تر است و ما اغلب روی این توابع کلون دار کار میکنیم تا جایی که لازم باشد[/FONT]
[FONT=tahoma]نکته اینکه در هر کجا وقتی آرگومانی را داخل علامت کلوشه یا [ ] نمایش دادند ، یعنی آن آرگومان قرار دادن یا ندادنش اختیاریست و اگر قرار ندهیم ، مقداری پیش فرض را خود زبان لوا قرار میدهد[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]تابع [/FONT][FONT=tahoma]io.open[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]io.open (filename [, mode])[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]همانطور که درباره ی این تابع در بالا تقریبا توضیح کامل داده شد (حتما خطوط بالا را مطالعه بفرمایئد) ، این تابع وظیفه ی باز کردن یک فایل جهت خواندن یا نوشتن را بر عهده دارد و قبل از عملیات خواندن و نوشتن ، باید از این تابع استفاده شود . این تابع ، مقدار عددی هندل آن فایل را برمیگرداند که اغلب در توابع کلون دار این مقدار بکارمان میآید[/FONT]
[FONT=tahoma]همانطور که مشخص است ، آرگومان [/FONT][FONT=tahoma]filename[/FONT][FONT=tahoma] ، مسیر فایلی که میخواهیم آنرا باز کنیم را باید بدهیم پس آرگومانی رشته ای است[/FONT]
[FONT=tahoma]آرگومان دوم [/FONT][FONT=tahoma]mode[/FONT][FONT=tahoma] همانطور که گفته شد چون داخل علامت کلوشه [ ] هست پس اختیاری است و بصورت پیش فرض اگر مقداری ندهیم ، مقدار "[/FONT][FONT=tahoma]r[/FONT][FONT=tahoma]" را میدهد. این آرگومان رشته ایست و نوع باز کردن یک فایل را از ما میخواهد و باید یکی از پارامترهای زیر را به عنوان رشته به آن داد :[/FONT]
[FONT=tahoma]رشته "[/FONT][FONT=tahoma]r[/FONT][FONT=tahoma]" : همانطور که قبلا گفته شد ، اگر قصد داریم محتوای یک فایل را بخوانیم ، قبل از آن باید آن فایل را برای خواندن باز کنیم که این رشته در آرگومان دوم همین کار را انجام میدهد اما اگر میخواهیم در فایل چیزی بنویسیم ، باید آن فایل را برای نوشتن باز کنیم و نمیشود فایلی را برای نوشتن باز کنیم و برای خواندن آنرا باز نکنیم اما محتوای آن فایل را بتوانیم بخوانیم (دقت کنیم ، باعث نمیشود که فایل خوانده شود . فقط به منظور خواندن ، آنرا باز میکند)[/FONT]
[FONT=tahoma]رشته "[/FONT][FONT=tahoma]w[/FONT][FONT=tahoma]" : فایل را برای نوشتن باز میکند (دقت کنیم ، باعث نمیشود که فایل خوانده شود . فقط به منظور خواندن ، آنرا باز میکند)[/FONT]
[FONT=tahoma]رشته "[/FONT][FONT=tahoma]a[/FONT][FONT=tahoma]" : برای نوشتن یا خواندن ، فایل را از ادامه باز میکند و میشود مثلا فایل را از ادامه ی آخرین سطر نوشت اما مثلا "[/FONT][FONT=tahoma]w[/FONT][FONT=tahoma]" فایل را از ابتدا اور رایت میکند و ...[/FONT]
[FONT=tahoma]یک رشته ی دیگر هم هر کدام یک علامت + در آخر میگیرند که برخلاف توضیحات سایتش ، مثل حالت عادی باعث اوررایت میشود (چیزی که باعث آپدیت میشود فقط رشته ی "[/FONT][FONT=tahoma]a[/FONT][FONT=tahoma]" هست)[/FONT]
[FONT=tahoma]باز هم آخر همه ی این رشته ها را اگر کلمه ی [/FONT][FONT=tahoma]b[/FONT][FONT=tahoma] بنویسیم یعنی اگر بنویسیم "[/FONT][FONT=tahoma]rb[/FONT][FONT=tahoma]" یا "[/FONT][FONT=tahoma]wb[/FONT][FONT=tahoma]" یا "[/FONT][FONT=tahoma]ab[/FONT][FONT=tahoma]" یعنی اینکه بجای فایل متن و [/FONT][FONT=tahoma]txt[/FONT][FONT=tahoma] ، میخواهیم فایل باینری را برای خواندن یا نوشتن یا آپدیت کردن ، باز کنیم (فایل باینری هم هر فایلی را که با [/FONT][FONT=tahoma]notepad[/FONT][FONT=tahoma] باز کنیم و غیر از متن ، علامت های درهم نوشته شده باشد را میگویند)[/FONT]
[FONT=tahoma]تابع [/FONT][FONT=tahoma]io.open[/FONT][FONT=tahoma] تنها تابع مهم قسمت [/FONT][FONT=tahoma]file i/o[/FONT][FONT=tahoma] است که برایش علامت همچین تابعی با کلون در نظر گرفته نشده . حالا توابع کلون دار[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]تابع [/FONT][FONT=tahoma]file:lines[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]file:lines[/FONT][FONT=tahoma]()[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]اول اینکه همانطور که گفته شد ، قبل از استفاده از این تابع ، باید فایل مورد نظر را در حالت خواندن باز کنیم یعنی [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]io.open (filename , "r")[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]اگر فایل مورد نظر بصورت بایتی هست ، باید رشته ی [/FONT][FONT=tahoma]b[/FONT][FONT=tahoma] را به آخر آن اضافه کرد[/FONT]
[FONT=tahoma]این تابع ، یک تابع [/FONT][FONT=tahoma]iterator[/FONT][FONT=tahoma] یا تابع تکرار کننده هست که هر بار ، یک خط از فایل مورد نظر را میخواند (تابع [/FONT][FONT=tahoma]iterator[/FONT][FONT=tahoma] قبلا در موضوع جداگانه ای توضیح داده شده است. در حالت کلی تابعی است که عملی را آنقدر انجام دهد که مقدارش [/FONT][FONT=tahoma]nil[/FONT][FONT=tahoma] شود)[/FONT]
[FONT=tahoma]همانطور که در تاپیک آموزش [/FONT][FONT=tahoma]iterator[/FONT][FONT=tahoma] ها بررسی شد ، تابع [/FONT][FONT=tahoma]iterator[/FONT][FONT=tahoma] بصورت عادی فراخوانی نمیشود و باید با یک حلقه ی تکرار که حلقه ی [/FONT][FONT=tahoma]for[/FONT][FONT=tahoma] برای آن رایج است ، فراخوانی شود . اگر مایل به نحوه ی عملکرد این تابع هستید ، ابتدا آن آموزش را مطالعه بفرمائید . این تابع هم این گونه فراخوانی میشود :[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]for OneLine in file:lines() do[/FONT]
[FONT=tahoma]--[/FONT][FONT=tahoma]body[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]متغییر [/FONT][FONT=tahoma]OneLine[/FONT][FONT=tahoma] ، در هر بار تکرار ، یک خط از فایل خوانده شده را برمیگرداند . حالا متغییر [/FONT][FONT=tahoma]OneLine[/FONT][FONT=tahoma] دلخواهی است و میتواند هر متغییری که خودتان تعریف میکنید باشد[/FONT]
[FONT=tahoma]این تابع آنقدر تکرار میشود که تمام خط های فایل مورد نظر تکرار شود[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]تابع [/FONT][FONT=tahoma]file:read[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]file:read[/FONT][FONT=tahoma](···)[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]اول اینکه همانطور که گفته شد ، قبل از استفاده از این تابع ، باید فایل مورد نظر را در حالت خواندن باز کنیم یعنی [/FONT]
[FONT=tahoma][[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]io.open (filename , "r")[/FONT]
[FONT=tahoma][/[/FONT][FONT=tahoma]CODE[/FONT][FONT=tahoma]][/FONT]
[FONT=tahoma]اگر فایل مورد نظر بصورت بایتی هست ، باید رشته ی [/FONT][FONT=tahoma]b[/FONT][FONT=tahoma] را به آخر آن اضافه کرد[/FONT]
[FONT=tahoma]تابع بالا ، فایل را بر اساس چیزی که ما میگوییم ، میخاند . اینکه بر چه اساسی بخواند ، یک آرگومان به عنوان ورودی به این تابع میدهیم که مشخص کننده ی نوع خواندن آن است . این ورودی ممکن است رشته یا عدد باشد که در ادامه توضیح میدهیم :[/FONT]
[FONT=tahoma]رشته ی [/FONT][FONT=tahoma][CODE]"*n"
. دقیق کار این آرگومان مشخص نیست اما در توضیحات سایت آمده که عدد را میخواند و عدد را برمیگرداند
رشته ی
کد:
"*a"
که یکی از مهمترین آرگومان ورودی این تابع است ، باعث میشود این تابع کل فایل را بخواند و کل متن آنرا برگرداند (دقت کنید اگر فایل بزرگ باشد (مثلا فایل ویدئویی بالای 200 مگ و ...) ، این تابع نمیتواند کل متن فایل را در داخل یک متغییر بریزد و در واقع نمیتواند کل فایل را یک دفعه بخواند . در این مواقع باید با تابع iterator ای که در بالا توضیح داده شد file:lines ، خط به خط فایل را جداگانه بخوانیم یا از آرگومان دیگری که در ادامه برای این تابع توضیح داده میشود استفاده کنیم).
رشته ی
کد:
["*l"/CODE][/FONT][FONT=tahoma] طبق توضیحات سایت لوا ، باعث خوانده شدن خط بعدی میشود[/FONT]
[FONT=tahoma]در آرگومان دیگر از همین تابع [/FONT][FONT=tahoma]file:read[/FONT][FONT=tahoma] ، بجای رشته های بالا ، اگر عدد وارد کنیم ، این تابع فقط همان تعداد متن را از ابتدای آن فایل میخواند . مثلا اگر بنویسیم [/FONT][FONT=tahoma][CODE]file:read(20)
باعث میشود 20 کاراکتر اول از آن خط خوانده شود . برای اینکه فایل هر تعداد کاراکتر خاص را پی در پی بخواند یعنی مثلا هر 20 کاراکتر 20 کاراکتر را بخواند ، مشخص است که باید از یک حلقه ی تکرار با این تابع استفاده کنیم و یا تابع iterator این کار را کنیم

تابع file:write

[CODE]
file:write(···)
[/CODE]

اول اینکه همانطور که گفته شد ، قبل از استفاده از این تابع ، باید فایل مورد نظر را در حالت خواندن باز کنیم یعنی
[CODE]
io.open (filename , "w")
[/CODE]
اگر فایل مورد نظر بصورت بایتی هست ، باید رشته ی b را به آخر آن اضافه کرد
هر آرگومانی از نوع عدد یا رشته به تابع بالا بدهیم ، آنرا در فایل مورد نظر مینویسد . برای تبدیل انواع داده ای جز عدد و رشته ، از توابع tostring و string.format استفاده کنید قبل از نوشتن
این تابع میتواند هر تعداد آرگومان داشته باشد که به ترتیب این تابع ، آرگومان ها را پشت سر هم مینویسد

تابع file:close

[CODE]
file:close()
[/CODE]

این تابع هیچ آرگومانی را به عنوان ورودی نمیگیرد و مقداری را هم برنمیگرداند . این تابع باعث بستن فایلی که باز کردیم میشود . اگر فایل مورد نظر را با این تابع نبندیم ، موقع حذف آن ، سیستم پیام file in use را میدهد و تا زمانی که نرم افزار مورد نظر (AMS و ...) را نبندیم و یا گاها سیستم را ریستارت نکنیم ، فایل را نمیتوانیم حذف کنیم



مثال ها :

1) میخواهیم فایلی را بنام Document.txt در پوشه اصلی (CD_Root) بخوانیم (در فایل Document.txt متن دلخواه را وارد کنید و ذخیره کنید) :

[CODE]
FileHandle = io.open("Document.txt", "r");
FileContent=FileHandle:read("*a");
Dialog.Message("Notice", FileContent, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
FileHandle:close();
[/CODE]

خوب اول باید فایل مورد نظر باز شود پس از تابع io.open استفاده میکنیم و در آرگومان اول آن ، مسیر فایل را میدهیم. در آرگومان دوم چون میخواهیم فایل را بخوانیم ، پس برای خواندن باید آنرا باز کنیم و چون فایل txt هست یعنی متن در هم نیست پس فایل باینری نیست پس در آرگومان دوم آن ، فقط رشته ی "r" را وارد میکنیم (دقت کنید حروف کوچک و بزرگ را) . فایل Document.txt را برای خواندن باز میکند و عددی را به عنوان هندل این فایل ، برمیگرداند پس در متغییر این تابع که FileHandle هست ، هندل این فایل ذخیره میشود
همونطور که گفته شد ، در توابع های کلون دار که در بالا ذکر شد ، بجای file یعنی قبل از علامت کلون گفتیم که باید از هندل فایلی که از خروجی تابع io.open استفاده میشود (در مثال بالا همان متغییر FileHandle ) استفاده کنیم. یعنی قبل از توابع کلون دار ، در مثال بالا ، باید بنویسیم FileHandle که تابع باید بداند که به کدام فایل این عملیات را انجام دهد (همانطور که گفته شد ، در توابع کلون دار ، مسیر فایل از آرگومان تابع حذف شد و به هندل فایل قبل از علامت کلون انتقال داده شد)
پس برای خواندن فایل باید از تابع FileHandle:read استفاده کنیم . آرگومان رشته ی "*a" در این تابع یعنی اینکه کل محتوای فایل را بخوان و در متغییر خروجی این تابع که FileContent است بریز
خط بعد هم که محتوا را چاپ میکند با پیغام
خط آخر هم که مثل ساختار فایل های کلون که در خط بالا گفته شد باید قبل از علامت کلون ، از هندل فایل استفاده کرد ، پس FileHandle:close() باعث بستن فایلی که هندل FileHandle داشت میشود . دقت کنید قبل از استفاده از از این تابع (مثلا موقعی که فایل خوانده شد و پیام داد در خط سوم) اگر فایل مورد نظر را بخواهیم حذف کنیم ، با پیام file in use ویندوز مواجه میشویم اما بعد از خط آخر میتوانیم حذف آنرا


2) متنی را داخل فایل Document.txt در پوشه اصلی بنویسیم :

[CODE]
FileHandle = io.open("C:\\Users\\UserName\\Documents\\AutoPlay Media Studio 8\\Projects\\file io\\CD_Root\\Document.txt", "w");
FileContent=FileHandle:write("this is a write test into taste file");
FileHandle:close();
[/CODE]

اگر دیدید فقط با آوردن رشته ی "Document.txt" عمل نمیکند ، رشته ی کامل مسیر را بصورت دستی بیاورید (بجای UserName ، نام کاربری خود را در رشته ی اول بدهید) . حتی سعی کنید از متغییر _SourceFolder هم استفاده نکنید شاید جواب ندهد
چون قصد نوشتن داشتیم پس باید برای نوشتن باز کنیم
دقت کنید در مثال بالا (موقع نوشتن) ، حتی اگر فایل مورد نظر هم وجود نداشته باشد ، ابتدا باید آنرا باز کرد برای نوشتن و بسیار مهم است این نکته

3) در این مثال ، فایل Document.txt در پوشه ی اصلی را خوانده و در پیامی چاپ و بعد از آن متن هایی به آن میخواهیم اضافه کنیم :

[CODE]
Path="C:\\Users\\UserName\\Documents\\AutoPlay Media Studio 8\\Projects\\file io\\CD_Root\\Document.txt";
ReadHandel = io.open(Path, "r");
FileContent=ReadHandel:read("*a");
Dialog.Message("Notice", FileContent, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
WriteHandel = io.open(Path, "a");
WriteHandel:write("\n","this line is one line remain to last line","\n","this line is last line . End")
ReadHandel:close();
WriteHandel:close();
[/CODE]

بجای UserName ، نام کاربری خود را در رشته ی اول بدهید
اولا چون هم میخواهیم بنویسیم و هم بخوانیم پس باید 2 بار فایل را باز کنیم . یکبار برای خواندن که "r" را در آرگومان مینویسیم و در متغییر ReadHandel ذخیره کردیم پس هر تابعی مربوط به خواندن مثل خط سوم را همراه با این هندل و متغییر میآوریم و یکبار دیگر برای نوشتن هم باید فایل را باز کرد (در خط پنجم) و در متغییر WriteHandel ، هندل این فایل برای نوشتن را ذخیره کردیم . منتها از "w" به عنوان آرگومان این تابع استفاده نکردیم چون میخواستیم ، در ادامه ی آن متن اضافه کنیم و اوررایت نکنیم . اگر از "w" استفاده میکردیم ، متنهای قبلی پاک میشد پس برای آپدیت و اضافه کردن متن ، از رشته "a" بجای "w" در آرگومان این تابع استفاده کردیم
دوما در خط 3 تا مانده یه آخر هم ، باید از هندلی که برای آپدیت کردن در خط 5 داخل متغییر WriteHandel ریختیم ، استفاده کنیم . این تابع ، دانه دانه آرگومان ها را شروع به اضافه کردن در فایل مورد نظر میکند یعنی اول ، آرگومان اول را که باعث اینتر زدن یا رفتن به خط بعد در فایل میشود را مینویسد و بعد آرگومان دوم که یک متن است و سپس آرگوامن بعدی که باز هم به خط بعد میرود و سپس آرگومان آخر را که متنی دیگر است
در دو خط آخر هم که چون 2 بار فایل را باز کردیم ، یعنی یکبار برای خواندن و یکبار هم برای نوشتن ، پس حتما حتما باید 2 بار آنهم هر بار با هندل های مورد نظر (یکبار با هندل خواندن و یکبار هم با هندل نوشتن) فایل را ببندیم پس به این ترتیب ، ReadHandel:close() و WriteHandel:close() را در 2 خط آخر مینویسیم (این 2 خط آخر یکی از نکات بسیار مهم است که نباید فراموش کرد)

4) یک فایل pdf بنام OldPdf در پوشه سورس ایجاد کنید . با کد زیر ، اطلاعات فایل را خوانده و در فایل txt با نام NewPdf میریزد :

[CODE]
PathSource="C:\\Users\\UserName\\Documents\\AutoPlay Media Studio 8\\Projects\\file io\\CD_Root\\OldPdf.pdf";
PathExit="C:\\Users\\UserName\\Documents\\AutoPlay Media Studio 8\\Projects\\file io\\CD_Root\\NewPdf.txt";
FileRead=io.open(PathSource ,"rb");
FileWrite=io.open(PathExit ,"wb");
PdfContent = FileRead:read("*a");
FileWrite:write(PdfContent);
FileRead:close();
FileWrite:close();
[/CODE]

بجای UserName ، نام کاربری خود را در رشته ی اول بدهید
هر فایل pdf را که با notepad باز کنید ، میبینید که کلمات درهم برهم نوشته شده است پس فایل باینری ست و برای باز کردن (چه برای خواندن یا نوشتن) باید بصورت باینری باز شود پس موقع باز کردن ، در آخر دومین آرگومان ، کاراکتر b را اضافه میکنیم (این بسیار مهم است) یعنی در خط 3 و 4
خط 5 هم کل محتوای فایل pdf را میخواند و در خط بعد هم کل این محتوا را در داخل فایل NewPdf.txt مینویسد (میتوانیم حتی برای این فایل ، هر پسوند دیگر یا حتی بدون پسوند ذخیره کنیم و در نظر بگیریم)
حالا فایل تکست NewPdf را اگر با نرم افزاری که فایل سورس اصلی را که acrobat reader بود اجرا کنید ، میبینید اجرا میشود و نحوه ی کپی کردن اطلاعات یک فایل میتواند این روش باشد . اما دقت کنید که اگر فایل حجیم باشد (مثلا فایل ویدئویی بالای 100 مگ) بسته به میزان رم ، اطلاعات نمیتواند داخل یک متغییر ذخیره شود . در این صورت باید خط به خط اطلاعات باینری فایل مورد نظر خوانده شود و داخل یک آرایه ذخیره شود (اگر از این روش ، یعنی از تابع iterator استفاده و اطلاعات را داخل آرایه بریزیم ، دیگر نمیشود اطلاعات فایل مبداء را مثل کد بالا ذخیره کنیم (ذخیره میشود) اما دیگر کدهای ذخیره شده در فایل قابل استفاده نیست و فایل اجرا نمیشود. کلا برای اجرای فایل ، ظاهرا یک روش وجود دارد و آنهم خواندن یکباره ی کل فایل و ذخیره در فایل جدید است)

5) کد زیر ، محتوای فایل OldFile را خط به خط میخواند :

[CODE]
PathSource="C:\\Users\\UserName\\Documents\\AutoPlay Media Studio 8\\Projects\\file io\\CD_Root\\OldPdf.pdf";
NewFile={}
Counter=1;
FileRead=io.open(PathSource ,"rb");
for Line in FileRead:lines() do
NewFile[Counter]=Line;
Dialog.Message("FileLine", NewFile[Counter], MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
Counter=Counter+1;
end
FileRead:close();
[/CODE]

در خط 5 ، تابع تکرار کننده (iterator) ی FileRead:lines را اجرا و هر بار ، هر خط را در متغییر Line ذخیره میکند
همانطور که گفته شد ، اگر با این روش ، اطلاعات خوانده شده را در فایلی ذخیره کنیم ، آن فایل قابلیت اجرا ندارد و تنها روش برای این کار ، خواندن یکباره ی کل محتویات فایل است






حالا به قضیه ی توابع file i/o هایی که بدون علامت کلون هستند میپردازیم :

همانطور که گفته شد ، توابع بدون کلون ، مسیر فایل یا هندل فایل را بجای اینکه قبل از علامت کلون دریافت کنند ، داخل آرگومان و ورودی توابع شان دریافت میکنند

تابع io.input

[CODE]
io.input ([file])
[/CODE]

بعد از تابع io.open و باز کردن فایل ، تابع io.input باعث میشود اگر در تابع ای که مربوط به عمل خواندن میشود (از این به بعد هر جایی تابع گفتیم ، منظور تابع file i/o بدون عملگر کلون است) ، مسیر فایل را ذکر نکنیم ، اتوماتیک هندل و مسیر این فایل که داخل آرگومان file که از هندل خروجی تابع io.open داده بودیم را ست میکند در غیر این صورت ، باید در همه ی آرگومان های بقیه ی توابع ، هر کجا آرگومانی بنام file را دیدیم ، مسیر کامل فایل را به آن بدهیم

تابع io.read

[CODE]
io.read (···)
[/CODE]

که باید بصورت زیر نوشته شود :

[CODE]
io.input():read
[/CODE]

و دقیق کار تابع کلون دارfile:read را میکند. یا باید در خط بالا ، قبل از علامت کلون ، از خروجی متغییر io.input که قبلا تعریف کرده بودیم ، استفاده کنیم

تابع io.output

[CODE]
io.output ([file])
[/CODE]

در آرگومان آن ، بجای file از خروجی تابع io.open استفاده میکنیم و دقیق برعکس تابع io.input ، موقع کار با تابع نوشتن یعنی تابع io.write مورد استفاده قرار میگیرد

تابع io.write

[CODE]
io.write (···)
[/CODE]

هر چه در آرگومان آن نوشته شود را در فایل مینویسد . اما باید به این صورت فراخوانی شود :

[CODE]
io.output():write
[/CODE]

یا قبل از عملگر کلون ،باید از متغییر استفاده شده در تابع io.output استفاده کنیم

تابع io.close

[CODE]
io.close ([file])
[/CODE]

باعث بشته شدن فایل مورد نظر میشود

تابع io.lines

[CODE]
io.lines ([filename])
[/CODE]

همان کار تابع file:lines را انجام میدهد.
بجای filename باید اسم فایل را نوشت

تابع io.type

[CODE]
io.type(obj)
[/CODE]

یکی از توابع کاربردی که در قسمت توابع کلون دار وجود ندارد ، این تابع هست که اگر فایلی باز شده بود ، مقدار رشته ی "file" را برمیگرداند و اگر بسته بود مقدار رشته ی "closed file" را برمیگرداند و اگر ارور بدهد ، nil را
در آرگومان این تابع هم بجای obj ، مقدار خروجی تابع io.open را که همان هندل فایل مورد نظر بود را وارد کنید



مثال بدون توضیح :
1)

[CODE]
-- Opens a file in read
file = io.open("test.lua", "r")

-- sets the default input file as test.lua
io.input(file)

-- prints the first line of the file
print(io.read())

-- closes the open file
io.close(file)

-- Opens a file in append mode
file = io.open("test.lua", "a")

-- sets the default output file as test.lua
io.output(file)

-- appends a word test to the last line of the file
io.write("-- End of the test.lua file")

-- closes the open file
io.close(file)
[/CODE]



2)

[CODE]
-- Opens a file in read mode
file = io.open("test.lua", "r")

-- prints the first line of the file
print(file:read())

-- closes the opened file
file:close()

-- Opens a file in append mode
file = io.open("test.lua", "a")

-- appends a word test to the last line of the file
file:write("--test")

-- closes the open file
file:close()
[/CODE]
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود مجموعه ابزار و ماژول و dll هایی برای اتوپلی تحت عنوان نرم افزاری بنام AMSSpecialist Tools 4.0 :

لینک دانلود :

AMSspecialist Tools

(من لینک دانلود رو چک نکردم)
یک نرم افزار جداگانه هست که بعد از نصب کردن ، میتونین توی مهمترین قسمتش که Gallery باشه برین و از اونجا به لیست عظیمی از dll هایی که از جاهای مختلف جمع آوری شد برای افزایش کارایی پروژه تون استفاده کنین و همینطور میتونین از همین قسمت Gallery ، به ماژول های لوا و همینطور توابعی که این نرم افزار AMSSpecialist برای اتوپلی بصورت آماده نوشت (مثل توابع مربوط به رشته و ...) رو میتونیم استفاده کنیم بنابراین بسیار کاربردی هست
علاوه بر اینا ، ابزارهای مختلف زیاد دیگه ای هم داره
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
توابع Iterator در لوا :

iterator به معنای لغوی تکرار کننده هست. در واقع در لوا ، ایتریتور به تابعی میگویند که با استفاده از هر نوع حلقه ای (مثل for و while و repeat که در بین این ها for رایج هست) ، آن تابع تکرار میشود تا زمانی که اولین مقدار بازگشتی آن تابع nil شود
ساختار کلی iterator ها به شکل زیر است :


ایتریتورها میتوانند بصورت مستقیم از حلقه ها فراخوانی شوند (حلقه ی for) یا بصورت غیر مستقیم که در این صورت از کلمه ی کلیدی return استفاده میشود .
قبل از همه اول به مقدمه میپردازیم
همانطور که در موضوعات قبل بیان شد ، iterator ، نام یک تابع است و تابع iterator بالا که نامش FuncName هست ، 2 مقدار ورودی (آرگومان first و secand) و 2 مقدار خروجی (مقادیر out_1 و out_2) دارد که برای فراخوانی و استفاده از خروجی و مقادیر آن در حالت معمول و عادی به این روش است (مثلا فرض میکنیم نوع آرگومان ها ، رشته اند) :

کد:
[/FONT]
[FONT=tahoma]inp_1,inp_2=FuncName("Word","Hello")[/FONT]
[FONT=tahoma]

که در اینجا مقدار out_1 داخل متغییر inp_1 و مقدار out_2 داخل متغییر inp_2 ذخیره میشود
کلمه ی کلیدی in : کلمه ی کلیدی ایست که در حلقه ی for بکار میرود و برای تکرار یک تابع (iterator) تا اولین مقدار (بازگشتی) nil شدن آن بکار میرود . بطوری که در سمت چپ آن ، نام متغییری را مینویسیم که مقادیر آن تابع مورد نظر بازگشت میدهند و در سمت راست آن ، نام تابع iterator و همچنین مقادیر آرگومان آنرا برای فراخوانی تابع مینویسیم

نکته ها :
1) فراخوانی تابع معمولی که با علامت پرانتز انجام میشود اما تابع ایتریتور بجایش از علامت ویرگول (کاما) استفاده میشود یعنی آرگومان ها با نام تابع بجای علامت پرانتز ، با ویرگول از هم جدا میشوند . مشخص است که اگر تابع ایتریتوری آرگومان نداشته باشد ، فقط نام آنرا فراخوانی میکنیم بدون هیچ علامت ویرگول یا پرانتز ای
ایتریتورها فقط 2 جا فراخوانی میشوند . یا در حلقه ی for (منظور کنار کلمه ی کلیدی in در خطی که حلقه تعریف میشود نه داخل حلقه) یا به عنوان مقدار بازگشتی در تابعی دیگر (که در این صورت ، غیر مستقیم میشود)
بدیهی است که در هر کجای دیگر غیر از این حالت ، تابع ایتریتور فراخوانی شود (مثلا داخل حلقه ی for یا حتی خارج از آن) ، مثل حالت عادی ، برای فراخوانی تابع ایتریتور ، از علامت تابع که پرانتز بود استفاده میکنیم که در این صورت از ساختار تابع ایتریتور بالا استفاده نمیشود و مثل توابع معمولی بکار میاید (مثلا حتی اگر در حلقه for هم تابع ایتریتور را فراخوانی کنیم ، همیشه برای هر بار تکرار ، هر دو آرگومان تابع ایتریتور برابر مقدار اولیه ی خود میشوند)
2) نکته ی دیگر اینکه تعداد آرگومان های تابع ایتریتور نمیتواند بیش از 2 تا باشد (بصورت استاندارد مشکلی ندارند اما اگر آرگومان سوم به بعد در تابع ایتریتور فراخوانی شوند ، به عنوان nil شناخته میشود حتی اگر مقدار داشته باشد اما خروجی تابع میتواند هر چند تا باشد)
3) نکته ی بسیار حائز اهمیت این است که عملکرد iterator ها به این گونه است که ابتدا مقادیری که در حلقه ی for برای آرگومان های تابع iterator در نظر گرفتیم (در مثال بالا همان رشته های "Word" و "Hello") مثل حالت عادی ، به ترتیب در آرگومان های تابع شان جایگذاری و مقدار دهی میشوند (یعنی "first="Word و "secand="Hello میشود) . در تکرار دفعات بعد ، همیشه آرگومان اول ، مقدارش همان مقدار اولیه و ثابت است یعنی در مثال بالا ، همیشه "first="Word هست حالا هر چقدر که میخواهد تابع تکرار شود . خوب باز هم معلوم است که مقدار out_1 داخل متغییر inp_1 و مقدار out_2 داخل متغییر inp_2 ذخیره میشود (یعنی در مثال بالا inp_1=5 و inp_2=10 میشود) . نکته ی مهم اینجاست که در دفعات دوم و به بعد ، همیشه مقدار اولین متغییر (inp_1 که 10 هست) ، بجای دومین آرگومان (که اولین بار رشته ی "Hello" بود) ارسال و جایگزین و مقدار دهی میشود (یعنی در دومین تکرار ، بجای عدد 10 بجای رشته ی "Hello" به آرگومان دوم که secand هست مقداردهی میشود و آرگومان اول یعنی first هم که همیشه مقدار اولیه ی خود که رشته ی "Word" بود را حفظ میکند)
4) ما هیچ کنترلی بر متغییرها و مقادیرشان در حلقه ی for نداریم یعنی نمیشود مثلا مقدار متغییر inp_1 را که همان مقدار out_1 هست را (به منظور کنترل الگوریتم) از حلقه ی for تغییر داد . باید این کنترل ها را از خود تابع ایتریتور انجام داد . مثال این نکات در ادامه گفته خواهد شد
5) حلقه ی for تا آنجایی تکرار میشود که اولین مقدار بازگشتی تابع ایتریتور (یعنی مقدار out_1) برابر nil شود
6) در تابع ایتریتور ، اگر شرطی گذاشته شود (بدون اینکه مقدار nil را برگردانیم در هر کدام از حالات شرط) و اگر شرط نقض شود ، حلقه ی for از تکرار باز میایستد
7) در تابع ایتریتور (مثل متغییر محلی در حلقه ی for و ...) ، متغییر محلی کارایی ندارد و مثل متغییر عادی تا پایان آخرین تکرار این تابع ، مقدارش در هر بار تکرار محفوظ میماند.
8) تابع ایتریتور ، حتما باید مقداری را برگرداند (حداقل یک مقدار یا تابع یا هر چیز دیگری)
9) در لغات انگلیسی ، به اولین مقداری که در حلقه ی for به عنوان اولین آرگومان مقداردهی میشود (رشته ی "Word") میگویند invariant state (حالت ثابت) و به دومین مقدار ("Hello") میگویند متغییر کنترلی یا control variable

مثال ها :
1)
کد:
[/FONT]
[FONT=tahoma]function square(iteratorMaxCount,currentNumber)[/FONT]
[FONT=tahoma]                if currentNumber<iteratorMaxCount then[/FONT]
[FONT=tahoma]                currentNumber = currentNumber+1[/FONT]
[FONT=tahoma]                return currentNumber, currentNumber*currentNumber[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for i,n in square,3,0 do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "i : "..i.."\nn : "..n, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

ابتدا در خط 8 ، تابع ایتریتور square با مقادیر iteratorMaxCount=3 (که تا آخر ، موقع فراخوانی مجدد تابع ایتریتور ، هر بار این مقدار ثابت میماند ولو حتی متغییر iteratorMaxCount در تابع ایتریتور یا هر کجای دیگر تغییر کند) و currentNumber=0 مقدار دهی میشود و تابع ایتریتور اجرا میشود . چون داخل تابع ایتریتور شرط بکار رفته ، پس طبق نکاتی که گفته شد ، اگر شرط نقض شود ، دیگر حلقه ی for اجرا نمیشود. شرط تابع که کاملا واضح و نیاز به توضیح ندارد .
تابع ، مقدار 1 را به عنوان اولین مقدار که در متغییر i ذخیره میشود و مقدار 1 را باز هم به عنوان دومین مقدار که در متغییر n ذخیره میشود را بازمیگرداند . بعد هم که تمام دستورات حلقه ی for اجرا میشود پس در اینجا این دو مقدار را چاپ میکند .
برای اجرای بار دوم ، اولین آرگومان که iteratorMaxCount=3 بود ، تا ابد ثابت میماند. دومین پارامتر که currentNumber بود ، مقدار اولین متغییری که آخرین بار هر چه بود (متغییر i که مقدارش 1 بود) جایگزین و ارسال میشود یعنی این بار currentNumber=1 میشود . باز هم شرط برقرار است و اولین مقدار بازگشتی این بار 2 میشود که در i ذخیره و دومین مقدار هم که 4 میشود (2*2) که در n ذخیره میشود .
بار سوم باز هم iteratorMaxCount=3 و مقدار i که این بار 2 است به عنوان آرگومان دوم که currentNumber است ، مقداردهی میشود . در تابع ایتریتور ، اولین مقدار بازگشتی 3 و دومین مقدار بازگشتی 9 (3*3) میشود و در خروجی چاپ میشود . بار بعدی iteratorMaxCount=3 و currentNumber=3 میشود که شرط نقض شده و دیگر حلقه ی for از اجرا بازمیایستد
توجه : دقت کنیم که در مثال بالا ، مقدار آرگومان دوم تابع مان که currentNumber بود ، طبق آخرین مقدار currentNumber (که تصور کنید چون مقدار بازگشتی تابع مان currentNumber بود پس مقدار آرگومان دوم برای دفعه ی بعد ، از آخرین مقدار currentNumber) تغذیه میشود؛ این طور نیست. مقدار آرگومان دوم برای دفعه ی بعد ، همان مقدار اولین خروجی خود همان تابع هست (چه میخواهد اسمش همین currentNumber باشد مثل مثال بالا یا هر متغییر دیگری) . یعنی اگر یک متغییری مثلا بنام Value هم که بود و در اولین خروجی تابع قرار میگرفت و حتی اگر متغییر currentNumber هم در دومین خروجی تابع قرار میگرفت ، مقدار متغییر i (که همان برابر مقدار آرگومان یا ورودی دوم این تابع در دفعه ی بعد بود) همان برابر با اولین مقدار خروجی تابع که Value بود میشد

2) این مثال غلط است چون آرگومان تابع ، بیش از 2 تاست :

کد:
[/FONT]
[FONT=tahoma]function Init(a,b,c)[/FONT]
[FONT=tahoma]Dialog.Message("2", "a : "..a.."\nb : "..b, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]b=b+1[/FONT]
[FONT=tahoma]a=a-1[/FONT]
[FONT=tahoma]    function Sec(a,b)[/FONT]
[FONT=tahoma]    ABC = a+b+5[/FONT]
[FONT=tahoma]    return ABC,a,b[/FONT]
[FONT=tahoma]    end[/FONT]
[FONT=tahoma]return Sec(a,b)[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for Fh,fd,re in Init,10,20,30 do[/FONT]
[FONT=tahoma]Dialog.Message("15", "abc : "..Fh.."\na : "..fd.."\nb : "..re, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

3)

کد:
[/FONT]
[FONT=tahoma]function iter(first,secand)[/FONT]
[FONT=tahoma]first=first+1[/FONT]
[FONT=tahoma]local minuse=secand-1[/FONT]
[FONT=tahoma]                if secand~=1 and new==nil then[/FONT]
[FONT=tahoma]                return minuse,first[/FONT]
[FONT=tahoma]                else[/FONT]
[FONT=tahoma]                new=nil[/FONT]
[FONT=tahoma]                return nil[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for input,useless in iter,0,10 do[/FONT]
[FONT=tahoma]local multiple=input[/FONT]
[FONT=tahoma]multiple=multiple^2[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "input : "..input.."\nuseless : "..useless.."\nmultiple : "..multiple, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]                if input==5 then[/FONT]
[FONT=tahoma]                new="down"[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

در خط 12 که فراخوانی شد تابع ایتریتور در حلقه ، مقدار دهی انجام شد (first=0 که همیشه ثابت است در تکرار و اجرای دفعات بعد این تابع و secand=10) . همانطور که گفته شد ، در تابع ایتریتور (و هم هرحلقه ی تکراری) اگر متغییر محلی تعریف شود ، تا آخر اجرایش ، مثل متغییر سراسری ، مقدار قبل اش در آن حفظ میشود اما از بلاک خود خارج نمیشوند یعنی متغییر محلی ای که در تابع تعریف شد (اگر قبلا با همین نام ، متغییری نساخته باشیم) ، مقدارش در بلاک دیگر (مثل بالا که حلقه ی for است) ، nil میشود و برعکس . پس در مثال بالا نمیشود متغییر minuse را در حلقه ی for و متغییر multiple را در تابع ایتریتور فراخوانی کرد چون مقدارشان nil میشود
خوب در تابع ایتریتور ، شرط پابرجاست پس مقدار minuse که 9 میشود در متغییر input ذخیره میشود . حالا کدهای حلقه ی for اجرا میشود یعنی متغییرها چاپ میشوند و هم شرط (input==5) برقرار نیست تا متغییر new مقداردهی شود .
دراجرای بار دوم ، اولین آرگومان که ثابت هست یعنی first=0 هست (هر چند متغییر first در اجرای تابع ایتریتور در دفعه ی قبل ، یکی اضافه شده اما همونطور که گفته شد ، آرگومان های ایتریتور به این نوع مقادیر توجهی ندارد و مقدار آرگومان اول همیشه ثابت و برابر مقدار اولیه اش هست و آرگومان دوم هم برابر مقدار اولین متغییر (خروجی) که باز هم ربطی ندارد که هم نام متغییر قبل با هر الگوریمی در تهیه و مقداردهی آن متغییر باشد یا نه) و آرگومان دوم که همان اولین متغییر (خروجی) که در اینجا input و مقدارش 9 بود ، هست . بنابراین مثل دفعه ی قبل دستورات اجرا میشوند تا آرگومان secand یا همان متغییر input به 5 برسد . بعد حلقه ی for اجرا شده و چون مقدار input برابر 5 است ، متغییر new="down" میشود و در دفعه ی بعد اجرای تابع ایتریتور ، چون new مقدار دارد ، اولین خروجی تابع ، nil میشود که خود باعث توقف اجرای این حلقه میشود
توجه داشته باشیم که مثلا در حلقه ی for ، چون مقدار متغییر input همان مقدار آرگومان secand هست ، نمیتوانیم در این حلقه ، مستقیما مقدار input را عوض کنیم . یعنی مثلا input اگر به 5 رسیده باشد ، بگوییم input=1 کن .یعنی کنترل روی هر متغییر مخصوص به بلاک خودش ، جداست و یک روش آن ، کنترل توسط تعریف متغییر جدید میباشد


فراخوانی تابع iterator از تابعی دیگر (فراخوانی غیر مستقیم از حلقه ی for) :
حالت دیگر استفاده از تابع ایتریتور وجود دارد . در این حالت ، تابع ایتریتور از تابع دیگر (بصورت غیر مستقیم از حلقه ی for) فراخوانی میشود . در این حالت از کلمه ی کلیدی return در تابعی که تابع ایتریتور را فراخوانی میکند استفاده میشود
در این حالت ، 2 تابع میتوانند داخل هم قرار گیرند و یا جدا از هم باشند و نقطه اشتراک شان این است که بالاخره هر یکی باید دیگری (خارجی، داخلی) را فراخوانی کند
در این حالت ، بسته به استفاده و نوع فراخوانی مان از تابع ایتریتور (که علامتش ویرگول بود) ، هم میشود هر دو تابع را به عنوان تابع ایتریتور فراخوانی کرد و یا اینکه یکی از آنها را به عنوان تابع ایتریتور فراخوانی کنیم که در این صورت ، تابعی که بصورت عادی فراخوانی شده است (با علامت پرانتز)، فقط یکبار و بلافاصله بعد از آن ، تابعی که بصورت ایتریتور فراخوانی شده است (با علامت ویرگول) ، تا زمانی که nil را برگرداند ، تکرار میشود
اگر 2 تابع داخل هم قرار دهیم طوری که تابع داخلی بی نام باشد و به عنوان مقدار بازگشتی تابع خارجی باشد (کنار return) و تابع خارجی آنرا هم در حلقه ، بصورت عادی (نه بصورت ایتریتور) فراخوانی کنیم ، این تابع داخلی به عنوان تابع ایتریتور در نظر گرفته میشود
دقت داشته باشیم که در تابع ایتریتور ، هیچ گاه بیش از 2 تابع تو در تو (که تابع خارجی ، تابع داخلی را برگرداند) ، نمیشود استفاده کرد


مثال :
1)

کد:
[/FONT]
[FONT=tahoma]function list_iter (t)[/FONT]
[FONT=tahoma]local i = 0[/FONT]
[FONT=tahoma]local n = #t[/FONT]
[FONT=tahoma]                return function ()[/FONT]
[FONT=tahoma]                i = i + 1[/FONT]
[FONT=tahoma]                                if i <= n then[/FONT]
[FONT=tahoma]                                return t[i][/FONT]
[FONT=tahoma]                                end[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]   [/FONT]
[FONT=tahoma]t = {10, 20, 30}[/FONT]
[FONT=tahoma]for element in list_iter(t) do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", element, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

همانطور که در موضوعات قبل گفته شد ، در خط سوم ، علامت # تعداد آرایه ی t را در n ذخیره میکند که 3 است
در مثال بالا ، همونطور که از فراخوانی خط 13 (کنار حلقه for) پیداست ، چون تابع list_iter را با علامت پرانتز فراخوانی کردیم ، پس به عنوان تابع معمولی فراخوانی کردیم نه به عنوان تابع ایتریتور ، پس این تابع ، فقط یکبار اجرا میشود و از آنجایی که داخل این تابع ، تابع بی نام ای برگردانده شده است (خط 4) ، پس طبق مطلب بالا ، این تابع ، تابع ایتریتور ماست یعنی با اجرای این رویداد ، از 1 تا 3 ، فقط یکبار اجرا و تابع داخلی آن که از خط 4 تا 9 است ، به اندازه ای اجرا میشود تا مقدار nil را برگرداند و چون این تابع (خط 4 تا 9) تابع ایتریتور ماست ، پس باید مقداری را برگرداند
خوب چون تابع list_iter ما که در خط 13 فراخوانی شد ، تابع معمولی است ، پس معلوم است که هر چقدر میخواهد ، میتواند تعداد آرگومان داشته باشد و قواعد تابع ایتریتورها که در شکل اول آمده ، بر روی آن اعمال نمیشود اما از آنجا که خود تابع بی نام ای را برمیگرداند ، نمیتواند بیش از همین تابع ، مقدار و خروجی دیگری را بازگرداند
پس بعد از فراخوانی تابع list_iter و آرگومان t که آرایه هست به عنوان آرایه ، در خط دوم ، i=0 و n=3 میشود . (تا اینجا فقط همین یکبار اجرا میشوند و تمام) . وقتی در خط 4 به تابع ایتریتور میرسد ، در خط 5 ، مقدار i=1 میشود و چون در خط 6 شرط برقرار است (1<3) پس تابع ایتریتورمان [1]t را برمیگرداند که مقدارش 10 است . همانطور که میدانید ، این مقدار 10 که (اولین) مقدار بازگشتی تابع ایتریتورمان است ، در متغییر element در خط 13 ذخیره و در خط 14 چاپ میشود .
در اجرای بار بعد (چون تابع list_iter را در خط 13 بصورت عادی فراخوانی کردیم ، بدیهی است قضیه ی آرگومان های تابع ایتریتور اعمال نمیشود) دوباره تابع ایتریتورمان (خط 4 تا 9) تکرار میشود (تا شرط آن نقض شود) . پس در خط 5 مقدار i=2 میشود (قبلا گفته شد که متغییر محلی ، در هر حلقه از جمله تابع ایتریتور ، در هر بار اجرا ، مقدار قبل خود را حفظ میکند که البته فقط در بلاک خودش در دفعات بعد ، حفظ میشود مقدارش و اعتبار دارد نه در بلاک های دیگر مثل حلقه ی for) و [2]t که 20 است در متغییر element در خط 13 ذخیره و در خط 14 چاپ میشود .
در اجرای بار بعد هم همینطور و در نهایت مقدار 30 چاپ میشود

2)

کد:
[/FONT]
[FONT=tahoma]function list_iter (t)[/FONT]
[FONT=tahoma]local n = #t[/FONT]
[FONT=tahoma]                if i < n then[/FONT]
[FONT=tahoma]                                return function ()[/FONT]
[FONT=tahoma]                                i = i + 1[/FONT]
[FONT=tahoma]                                return t[i][/FONT]
[FONT=tahoma]                                end[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]i=0[/FONT]
[FONT=tahoma]t = {10, 20, 30}[/FONT]
[FONT=tahoma]for element in list_iter,t do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", type(element).."\n"..element(), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

حالا اگر همان مثال ، کل تابع list_iter رو تابع ایتریتور در نظر بگیریم (در فراخوانی حلقه ی for در خط 13 ، از ویرگول استفاده کنیم) چه اتفاقی رخ میدهد؟ (با کمی تغییرات)
ابتدا در خط 11 مقدار i=0 و آرایه ی t تعریف شد
در خط 13 در حلقه ی for ، برای آرگومان ها از ویرگول استفاده شد پس یعنی کل تابع list_iter مان به عنوان تابع ایتریتور است و از آنجایی که همیشه اولین آرگومان تابع ایتریتور ثابت است و الان هم یک آرگومان بیشتر نداریم پس همیشه t مان ثابت و برابر آرایه ای که تعریف شد است
در خط 2 مقدار n=3 است و در خط 3 هم شرط برقرار است (0<3)
در خط 4 ، کل تابع بی نام (خط 5 تا 6) را به عنوان مقدار بازگشتی (که از نوع تابع هست) را در متغییر element ذخیره میکند . (پس element از نوع تابع است الان) که در خط 14 ، نوع این متغییر را که تابع است را مینویسد و در ادامه اش آنرا (element را) که تابع است ، فراخوانی میکند که در اینجا یعنی تابع elment که از خط 5 تا 7 است ، اجرا میشود . یعنی در خط 5 مقدار i=1 و در خط 6 ، این تابع مقدار [1]t را برمیگرداند را که 10 است را برمیگرداند و در خط 14 چاپ میکند
برای اجرای بار دوم هم که معلوم است چون تابع ایتریتور فراخوانی شده ی مان در خط 13 ، یک آرگومان دارد و همیشه آرگومان اول ثابت است ، پس دوباره دقیق به همان نحو قبلی ، تابع ایتریتورمان تکرار میشود . این بار مقدار i مان برابر 1 است . وقتی که در خط 14 تابع element فراخوانی میشود ، مقدار i در خط 5 برابر 2 و این تابع ، مقدار 20 را برمیگرداند و به همین منوال تا تعداد آرایه ها که 3 تاست ، تکرار میشود و مقادیرشان را چاپ میکند
در این مثال متغییر i از تابع بیرون کشیده شد وگرنه هر بار مقدارش 1 میشد و هر بار اولین عضو آرایه ی t را برمیگرداند. جای شرط هم عوض شد وگرنه مقدار 4 امین عضو از آرایه ی t را که مقدارش nil بود را برمیگرداند و باعث ارور میشد
اگر در خط 14 ، این کد را جایگزین میکردیم :

کد:
[/FONT]
[FONT=tahoma]Dialog.Message("Notice", type(element), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]

چون تابع بازگشتی (تابع بی نام) اجرا نمیشد ، پس مقدار i افزایش نمیافت و i همیشه برابر 0 می بود در تکرار دفعه ی بعد پس تابع تا ابد تکرار میشد
اگر آرگومان تابع ایتریتور list_iter در بالا ، 2 آرگومان میداشت و مقدار هر دو آرگومان مثل هم بودند ، بدیهیست که طبق نکاتی که گفته شد ، در اجرای بار دوم به بعد ، مقدار آرگومان دوم ، همان تابع بازگشتی بی نام است . مثلا به این گونه باشد (که چون دفعه ی دوم ، مقدار h ، تابع است در خط دوم ، دفعه ی دوم ، ارور میدهد) :

کد:
[/FONT]
[FONT=tahoma]function list_iter (t,h)[/FONT]
[FONT=tahoma]Dialog.Message("iterator function", h[1], MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]local n = #t[/FONT]
[FONT=tahoma]                if i < n then[/FONT]
[FONT=tahoma]                                return function ()[/FONT]
[FONT=tahoma]                                i = i + 1[/FONT]
[FONT=tahoma]                                return t[i][/FONT]
[FONT=tahoma]                                end[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]i=0[/FONT]
[FONT=tahoma]t = {10, 20, 30}[/FONT]
[FONT=tahoma]for element in list_iter,t,t do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", type(element), MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

3)

کد:
[/FONT]
[FONT=tahoma]function Init(a,b)[/FONT]
[FONT=tahoma]b=b+1[/FONT]
[FONT=tahoma]a=a-1[/FONT]
[FONT=tahoma]    function Sec(a,b)[/FONT]
[FONT=tahoma]    ABC = a+b+5[/FONT]
[FONT=tahoma]                if ABC<150 then[/FONT]
[FONT=tahoma]                                return ABC,a,b[/FONT]
[FONT=tahoma]                                end[/FONT]
[FONT=tahoma]    end[/FONT]
[FONT=tahoma]return Sec(a,b)[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for One,Two,Three in Init,10,20 do[/FONT]
[FONT=tahoma]Dialog.Message("Notic", "ABC : "..One.."\na : "..Two.."\nb : "..Three, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

در خط 13 در حلقه ، تابع Init با ویرگول نشانه گذاری شد پس یعنی کل تابع Init به عنوان تابعایتریتور است
همانطور که قبلا هم آشنا شدید با قضایا ، مختصرا توضیح داده میشود . a=10 و b=20 به تابع ایتریتور ارسال میشود. در خط 10 ، تابع داخلی اش فراخوانی میشود (اجرا میشود) . که در نتیجه مقدار ABC=35 و a=9 و b=21 میشود و به ترتیب این مقادیر به متغییرهای One و Two و Three ارسال و در آنها ذخیره میشوند . در اجرای بعد ، آرگوما دوم برابر اولین خروجی تابع (One) میشود پس a=10 و b=35 میشود . دوباره در خط 10 تابع داخلی با مقادیر داده شده به عنوان آرگومان، اجرا میشود و این ماجرا تا وقتی که شرط تابع داخلی نقض نشود ، ادامه دارد
همین مثال را میشود بصورت زیر نوشت :

کد:
[/FONT]
[FONT=tahoma]function Sec(a,b)[/FONT]
[FONT=tahoma]ABC = a+b+5[/FONT]
[FONT=tahoma]    if ABC<150 then[/FONT]
[FONT=tahoma]                return ABC,a,b[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]   [/FONT]
[FONT=tahoma]function Init(a,b)[/FONT]
[FONT=tahoma]b=b+1[/FONT]
[FONT=tahoma]a=a-1[/FONT]
[FONT=tahoma]return Sec(a,b)[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for One,Two,Three in Init,10,20 do[/FONT]
[FONT=tahoma]Dialog.Message("Notic", "ABC : "..One.."\na : "..Two.."\nb : "..Three, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

4)

کد:
[/FONT]
[FONT=tahoma]function equal(iteratorMaxCount,currentNumber)[/FONT]
[FONT=tahoma]                if currentNumber<iteratorMaxCount then[/FONT]
[FONT=tahoma]                currentNumber = currentNumber+1[/FONT]
[FONT=tahoma]                return currentNumber, currentNumber*currentNumber[/FONT]
[FONT=tahoma]                end[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]function squares(iteratorMaxCount)[/FONT]
[FONT=tahoma]return equal,iteratorMaxCount,0[/FONT]
[FONT=tahoma]end  [/FONT]
[FONT=tahoma] [/FONT]
[FONT=tahoma]for i,n in squares(3) do [/FONT]
[FONT=tahoma]Dialog.Message("Notice", "i : "..i.."\nn : "..n, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

این مثال شباهت زیادی به اولین مثالی دارد که گفته شد .
در خط 12 در حلقه ، squares بصورت عادی فراخوانی میشود پس تابع ایتریتورمان نیست . مقدار 3 به آرگومان تابع squares ارسال میشود که خود این تابع ، تابع ایتریتور را با نام equal برمیگرداند و فراخوانی میکند مقدار آرگومان اولش همانطور که مشخص است ، مقدار iteratorMaxCount که 3 تعیین شده و آرگومان دوم هم که 0 هست (یعنی iteratorMaxCount=3 و currentNumber=0) . این بدیهی و مشخص است چون تابع ایتریتور از اینجا مشخص و فراخوانی شد (منظور مقدار بازگشتی همین تابع یعنی خط 9 هست) پس در دفعات بعد آرگومان های تابع ایتریتور از همینجا مقدار دهی و تغذیه میشوند
در خط دوم چون شرط برقرار است ، پس تابع ایتریتور ، در اولین مقدار بازگشتی اش currentNumber را که در حال حاضر برابر 1 است را برمیگرداند که در متغییر i در خط 12 ذخیره میشود و در دومین مقدار بازگشتی اش همین متغییر به توان 2 را که باز هم مقدارش 1 میشود را باز میگرداند که در متغییر n ذخیره میشود .
در اجرای بار دوم ،همانطور که گفته شد ، تابع از خط 9 که فراخوانی تابع ایتریتور از آنجا شکل گرفت ، مقداردهی میشوند و همانطور که قبلا گفته شده بود اولین مقدار خروجی تابع ایتریتور یعنی مقدار متغییر i که فعلا 1 است در دومین آرگومان ارسالی که قبلا در خط 9 مقدار 0 بود ، جایگذین میشود و مقدار اولین آرگومان که iteratorMaxCount و برابر 3 بود تا آخر ثابت میماند . پس این دفعه ، مقدار currentNumber=1 میشود و با این اوضاع i=2 و n=4 میشود .
همین منوال را در اجرای بعدی پیش بروید متوجه خواهید شد که i=3 و n=9 میشود و در دفعه ی بعد دیگر شرط تابع ایتریتور نقض میشود


تکرار آرایه ها با استفاده از توابع next و pairs به عنوان تابع ایتریتور :
همانطور که میدانید ، میتوان با توابع اصلی لوا ، تمام مقادیر و شماره ی عضوها حتی عنصرها (key ها) را با این دو تابع فراخوانی کرد . این دو تابع زمانی چاره گشایی میکنند که در آرایه ای از key استفاده شده باشد . آرایه ی زیر را در نظر بگیرید :

کد:
[/FONT]
[FONT=tahoma]array={x=54,a="hello",7590,y="word"}[/FONT]
[FONT=tahoma]

به x و a و y در آرایه ی بالا ، key میگویند و 54 و "hello" و "word" مقادیرشان هستند
بدست آوردن key ها یعنی x و a و y بصورت عادی بدون استفاده از توابع next و pairs حداقل میشود گفت کار بسیار سخت و یا نشدنی ایست
این توابع ، وقتی به عنوان تابع ایتریتور استفاده شوند (یعنی در حلقه ی for) ، همه ی مقادیر و نام عنصرها (key ها)ی آن آرایه را برمیگردانند تا به عضو nil یا پوچ یا تعریف نشده برسند که با برگرداندن nil ، حلقه از اجرا بازمیایستد

1) تابع next :
قبل از گفتن این تابع به عنوان تابع ایتریتور (که در حلقه ی for بکار برود) ، بصورت تابع معمولی توضیح دهیم . این تابع 2 ورودی (آرگومان) میپذیرد و 2 خروجی (مقدار بازگشتی) میدهد . اولین آرگومانش ، اسم تابع مورد نظر است و دومین آرگومان آن که دلخواهی ست ، شماره ی آن عضوی از آرایه که عضو بعدی اش را میخواهیم میدهیم . خروجی هم مقدار بازگشتی اول اش ، شماره ی عضو بعدی ای که در آرگومان دوم قرار دادیم را برمیگرداند و مقدار بازگشتی دوم اش ، مقدار شماره ی بعدی شماره ای که در آرگومان دوم داده بودیم . مثال :

کد:
[/FONT]
[FONT=tahoma]t={32,28,65}[/FONT]
[FONT=tahoma]x,y=next(t,2)[/FONT]
[FONT=tahoma]Dialog.Message("Notice", x.."\n"..y, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]

در خط دوم ، اولین آرگومان تابع next را اسم آرایه ی مورد نظرمان که t است را میدهیم . حالا چون در دومین آرگومان اش عدد 2 گذاشتیم پس در اولین مقدار بازگشتی اش که x باشد ، شماره ی عضو بعدی 2 که 3 است (یعنی سومین key تابع t که 3 است) را برمیگرداند و در دومین مقدار بازگشتی اش که y باشد ، مقدار عضو بعدی 2 (یعنی مقدار عضو سوم از آرایه ی t) که 65 است را برمیگرداند
دومین آرگومان تابع next دلخواهی است (اگر در توضیحات سایت اصلی این تابع next هم دقت کنید در دومین آرگومان اش علامت کلوشه [ ] گذاشته است که این علامت یعنی آن آرگومان دلخواهی است گذاشتن و نگذاشتن اش) و اگر این آرگومان را مقداردهی نکنیم ، برابر nil بصورت پیش فرض میشود و اگر nil شود ، اولین شماره ی عضو (key) و اولین مقدار آرایه را برمیگرداند
حالا تابع next به عنوان ایتریتور :

کد:
[/FONT]
[FONT=tahoma]array={x=54,a="hello",7590,y="word"}[/FONT]
[FONT=tahoma]for k,v in next,array do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "key : "..k.."\nvalue : "..v, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

در مثال بالا ، در خط دوم ، چون با ویرگول فراخوانی شد تابع next پس نشان دهنده ی این است که این تابع هر چه که هست ، کل این تابع هر بار تکرار میشود . آرگومان اولش اش که معلوم بود و آرگومان دوم اش چون دلخواهی بود و فرض بر این است که از اولین عضو آرایه فراخوانی کنیم ، پس با قرار ندادن (که همان nil قرار دادن آرگومان دوم است) ، از اولین عضو آرایه فراخوانی میشود . k و v هم مثل مثال بالا مقادیر بازگشتی است که توضیح داده شد

2) تابع pairs :
به عنوان ورودی ، فقط اسم آرایه را میگیرد و خروجی اش دقیق مثل تابع next است چون این تابع وقتی فراخوانی شود ، تابع next را برمیگرداند (یعنی بصورت غیر مستقیم تابع next مان که به عنوان ایتریتور بود را برمیگرداند پس باید با علامت آرایه که پرانتز بود ، آرگومان اش مقداردهی شود) :

کد:
[/FONT]
[FONT=tahoma]array={x=54,a="hello",7590,y="word"}[/FONT]
[FONT=tahoma]for k,v in pairs(array) do[/FONT]
[FONT=tahoma]Dialog.Message("Notice", "key : "..k.."\nvalue : "..v, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);[/FONT]
[FONT=tahoma]end[/FONT]
[FONT=tahoma]

با تشکر از تمام بچه های گل انجمن پرشین کدرز و کاربران بقیه ی انجمن ها که در آموزش سهیم بودند (ممنون میشم به نیت کلیه ی امواتی که در این آموزش سهیم بودند ، فاتحه ای قرائت بفرمایید)
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
از این به بعد ، آموزش سری جدید اتوپلی و لوا رو میزارم .
بچه ها من آموزش ها رو توی گوگل درایو میزارم چون هم حجم خوبی میده و هم اینکه آپلود برام راحت تره و فعلا هم از لحاظ دسترسی مشکل نداره . حالا امکان داره که در آینده ، مثل قبل ، گوگل سیاست تحریم و این چیزها رو پیش بگیره و اگه دوست داشتین از همین الان ، یکی چمیدونم طرفند مستقیم کردن لینک هه ، چیه ، این کارها رو انجام بده



دانلود آموزش AMS قسمت 25

دانلود آموزش AMS قسمت 26




توضیح قسمت ها :

قسمت 25 => رفع و توضیح اشکالات و ارورهایی که در 28 قسمت قبل پیش اومده بود (به مدت 2:22 دقیقه و حجم 155 مگابایت)
قسمت 26 => نکات کاربردی و ریز و مهم درباره ی تابع و توضیح درباره ی قابلیت ها و ضعف های لوا و AMS (به مدت 4:6 دقیقه و حجم 267 مگابایت)
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 27


توضیح قسمت 27 => بلاک ها و متغییر محلی و آرایه های key دار و تغییر عملکرد یک تابع از قبل تعریف شده و توابع Iterator (به مدت 4:57 دقیقه و حجم 295 مگابایت)

*** تذکر :

1) این سری جدید از فیلم های آموزشی ، با rar5 فشرده سازی شدند یعنی برای اکسترکت کردن ، باید نسخه ی rar 5 به بالا از این نرم افزار رو داشته باشین

2) اگه موقع دانلود مشکل داشت ، حتما مرورگرتون رو عوض کنین و دانلود کنین (مثلا با مرورگر اپرا دانلود کنین) .

 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 28

دانلود آموزش AMS قسمت 29

دانلود آموزش AMS قسمت 30




توضیح قسمت ها :

قسمت 28 => آرایه ی چند بعدی و ماژول ها و رفع 3 اشکال بجا مونده از سری آموزش قدیمی (به مدت تقریبی 3 ساعت و حجم 166 مگابایت)
قسمت 29 => شی گرایی در لوا (به مدت 2:23 دقیقه و حجم 123 مگابایت)
قسمت 30 => فراآرایه و ارث بری در لوا (به مدت 1:43 دقیقه و حجم 109 مگابایت)

** تذکرات :

1) چون چند روز پیش که آموزش های قسمت 29 تا 31 رو آپلود کرده بودم ، تصویرش با تاخیر اجرا میشد و صدا و تصویر همزمان نبود ، مجبور شدم اون ها رو پاک کنم و دوباره رندر و آپلود کنم که آپلود این سری علاوه بر درست شدن قضیه ی تاخیر تصویر ، حجم کمتری هم داره

2) آموزش های سری جدید (از قسمت 29 و بعد از اون) با rar5 فشرده سازی شد پس برای اکسترکت کردن حتما باید نسخه ی 5 این نرم افزار rar رو داشته باشین

3) فایل های فشرده قابلیت recovery record دارن (به پست اول مراجعه کنین برای توضیحات)

4) برای دانلود ، از دانلودر مثل idm استفاده نکنید و از دانلودر خود مرورگر استفاده کنید . برای دانلود توسط دانلود مرورگر ، روی لینک کلیک راست و save as link رو بزنید .اگه موقع دانلود مشکل داشت ، حتما مرورگرتون رو عوض کنین و دانلود کنین (مثلا با مرورگر اپرا دانلود کنین)

5) حجم هر پارت ، جز آخرین پارت 200 مگابایت هست
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 31


قسمت 31 => شباهت ها و تفاوت های زبان لوا و اتوپلی با زبان #C و ویژال استودیو و آموزش سطحی ویژال استودیو و #C (به مدت 2:38 دقیقه و حجم 135 مگابایت)
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نکته درباره کمپوننت اتوات :

اولا اتوات ، نسخه ی 64 بیت اش رو نباید استفاده کرد یعنی فایل AutoItX3_x64.dll رو نباید استفاده کنیم
بعد اینکه کمپوننت اتوات رو در ویندوز 64 بیتی ، باید در پوشه ی SysWOW64 و در ویندوز 32 بیتی در پوشه ی System32 کپی و بعد ثبت کرد (با تابع System.RegisterActiveX هم میشه یک کمپوننت ای که میخوایم اضافه کنیم مثل همین اتوات رو ثبت کرد منتها باید قبل اش طبق چیزی که گفته شده ، در پوشه ی مناسبی طبق نسخه ی ویندوز کپی کرد)
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آقایون میخوام قسمت 24 تا 28 را حذف کنم چون هم اصولی کار نشد و هم اشتباهات این قسمت ها زیاد هست و هم بسیار مبتدی کار شده
حالا نظرتون چیه؟
ولی به احتمال زیاد حذف میکنم
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نکته درباره پترن ها (یادآوری) :


علامت ها تعیین کننده ی الویت هستند .
علامت مثبت + : یعنی حداقل یکی از اون الگو (پترن) باید پیدا بشه تا جوابی پیدا بشه و اگه هم اون پترن پشت سر هم بود ، تا آخرِ اون پترن رو برمیگردونه (بزرگترین نمونه) مثلا "+d%" کل اعداد رو برمیگردونه
علامت منفی - : یعنی بودن یا نبودن اون پترن مهم نیست (اگه بود ، توی نتیجه میاد و اگه نبود توی نتیجه نمیاد ولی بالاخره نتیجه پیدا میشه) یعنی به عبارت ریاضی اگه بخواد گفته شه ، حداقل صفر تا از اون الگو باید موجود باشه (به زبان عامیانه یعنی موجود بودن یا نبودن اش فرقی نداره) و اگه اون پترن پشت سر هم بود ، کوچیکترین نمونه ی اون پترن برگردونده میشه (توضیح این تیکه در آموزش ها اومد)
علامت ضرب * : مثل منفی ، بودن یا نبودن اون پترن براش مهم نیست اما مثل ضرب ، تا آخرِ اون پترن (بزرگترین پترن) رو برمیگردونه
علامت علامت سئوال ? (علامت سئوال بصورت انگلیسی) : مثل منفی ، بودن یا نبودن پترن براش مهم نیست ، اما فقط اولین کاراکتر از کل اون پترن رو برمیگردونه یعنی مثلا اگه در "586013 "پترن "?d%" رو بنویسیم ، ضمن توضیح الویت که گفتم ، فقط اولین کاراکتر رو که "5" هست را برمیگردونه




البته استثناهایی داره که توی آموزش بررسی شد
دقت کنیم ، همونطور که در آموزش بررسی شد اگه Magic کاراکترهای - و * و ? اگه به تنهایی فقط برای یک پترن (کلاس کاراکتر) بکار بره ، چون الویت اول رو ندارن ، ارور میده یعنی نمیتونیم به تنهایی بنویسیم "%d-" یا "%d*" یا "%d?" یا "[%d.abc%p]-" یا همه ی پترن ها و کلاس کاراکترهامون رو یکی از این 3 الویت بگیریم (مثلا 2 تا کلاس کاراکتر که هر 2 تا منفی باشن ، نمیشه ولی یکی منفی و یکی ضرب احتمالا میشه) . کلا باید پترن ها (کلاس کاراکترها) حداقل شامل یک دونه علامت با الویت بالاتر از بقیه ی پترنهای (کلاس کاراکترها) کناریش باشه (یا باید بدون علامت باشه که الویت اش برابر علامت مثبت + هست)
علامت کلاس کاراکتر کلوشه [] یعنی هر پترنی توش قرار بگیره ، ترتیب اش مهم نیست اما حداقل یکی از کاراکترهه (پترن ها) ی استفاده شده درکلوشه باید پیدا بشه تا نتیجه حاصل بشه
پس علامت های +-*? الویت ها رو عوض میکنن و علامت کلوشه ، ترتیب ها رو
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
قرار دادن پترن های آماده برای لوا :

نمونه کد اصلی برای جستجو که میدونیم این هست :

کد:
MainStr = "sa+lam----------236.200*35/2-abc.cbd-5"
LastChar = 0
var=false
while var==false do
FirstChar, LastChar, Content1 = string.find(MainStr, "Pattern",LastChar+1)
    if Content1==nil then
    var=true
    break ;
    else
    Dialog.Message("Notice", FirstChar.."\n"..LastChar.."\n"..Content1, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1) ;
    end
end

حالا میتونه توابع و حلقه و حتی بدنه ی متفاوت باشه

بجای رشته ی "Pattern" در آرگومان دوم تابع string.find پترن هایی که بچه ها میزارن رو میتونیم جایگزین اش کنیم



-------------------------------------------



یه چند تای اولی رو بزارم :

1)

کد:
"(%-?%d+)"
این پترن تمام اعداد (بدون علامت) به همراه اعداد با علامت منفی (اگه علامت منفی وجود داشت) رو پیدا میکنه.



2)


کد:
[/FONT]"(%-?%d+%.?%d*)"[FONT=Tahoma]
[/FONT]



همون کار بالا رو میکنه ، منتها اعداد اعشاری رو هم به حساب میاره (البته در این پترن دومی ، اگه بصورت این جوری نوشته بشه که عدد نوشته بشه و بعد فقط یک نقطه نوشته بشه ولی دوباره بعدش عدد نوشته نشه مثلا این جوری نوشته بشه .10 هم حساب میکنه که فعلا روش فکر نکردم که چجوری باید برداشت . شاید روشی وجود داشته باشه توی پترن ها یا نه ولی با تابع جداگانه ای که مینویسین میتونین دوباره پترن دیگه ای بنویسین تو اون تابع که چک کنین بعد از نقطه ، حتما عدد اومده باشه که این مشکل حل میشه)
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 32

تذکر *** : همونطور که قبلا گفتم ، از خود قسمت 25 تا قسمت 28 (یعنی 4 قسمت) رو حذف کردم یعنی همون قسمت هایی که طراحی یک اتوران رو کار کرده بودیم. دلیل اش هم باز هم که گفته بودم ، سادگی و پیشرفته نبودن کار و خطاهای زیاد (چون 3 سال پیش کمتر کدنویسی بلد بودم) و اصولی ننوشتن کدها بود. بجای اون 4 قسمت ، پیگیر طراحی اتوران در قسمت های آینده (15 تا 20 قسمت آینده) باشین
بنابراین در مجموعه ی آموزشی سری جدید (که از خود قسمت 29 به بعد بود) ، هر کدوم از اینها را 4 قسمت کم کنین یعنی قسمت 29 میشه همون قسمت 25 و قسمت 30 میشه قسمت 26 و غیرو ...
بنابراین این قسمت هم بجای اینکه قسمت 36 بشه ، قسمت 32 هه




قسمت 32 => توضیح تکمیلی شی گرایی در لوا ؛ کوروتین ها در لوا (توقف و ادامه ی اجرای کدها) با مثالی از اجرای پی در پی چند نرم افزار تا زمانی که پنجره ی نرم افزار لود شده ی قبلی بسته نشد توسط کوروتین ها (به مدت 4:17 دقیقه حجم 261 مگابایت)
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
Garbag Collector در لوا و آزاد کردن رم :

برای آزاد کردن حافظه بعد از حذف آرایه ای که از ریشه اون آرایه رو nil کردین (nil کردن اعضای اون آرایه مهم نیست و تاثیری در کار نداره) فقط کافیه تابع

کد:
collectgarbage();

را بدون هیچ آرگومان ورودی ای اجرا کنید (بعد از nil کردن ریشه ی آرایه یا متغییر) تا گربگ کالکتور لوا ، حافظه ای که برای اون آرایه در نظر گرفته بود رو آزاد کنه

مثال درست (این مثال درست هست چون آرایه از ریشه nil شد) . در یک رویداد این کد رو بنویسید تا رمتون تا 500 مگ اشغال بشه:

کد:
arr={};
for i=1,20000000 do
arr[i] = "abcdefghijklmnopqrstuvwxyz"
end

و در رویدادی که میخواین آزاد بشه رم تون از این آرایه ، این کد رو بنویسین :

کد:
arr=nil;
collectgarbage();


مثال نادرست (این مثال نادرست هست چون ریشه ی آرایه رو nil نکردیم و فقط کل اعضای اون آرایه رو nil کردیم که جواب نمیده) . در یک رویداد همون کد اولی :

کد:
arr={};
for i=1,20000000 do
arr[i] = "abcdefghijklmnopqrstuvwxyz"
end

در یک رویداد دیگه (که البته رمتون آزاد نمیشه و کد کار نمیکنه) :

کد:
for i=1,20000000 do
arr[i] = nil;
end

collectgarbage();
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام

یاهو (یاهو و گوگل نه . آوای خوشحالی منظورمه:green:) . آخه این الگوریتم به این سادگی چی بود که من نتونستم اون موقع که file i\o رو بررسی میکردم متوجه شم:). اینجاست که امام خامنه ای میگه به وعده ی خدا اعتماد داشته باشید (إِن تَنصُرُوا اللَّهَ يَنصُركُم) . حتما اون موقع اعتمادم کمتر بود :)

این کد رو برای تیکه کردن یک فایل بدین :

کد:
psdPath=_SourceFolder.."\\Document.pdf";
pdfSaveName = _SourceFolder.."\\New folder\\SaveCodeLine";
--film.mpg New folder
pdfOpen = io.open(psdPath , "rb");
Counter = 1;
while (value==nil) do
psdRead = pdfOpen:read(20000);
    if (psdRead~=nil) then
    saveHandle = io.open(pdfSaveName..Counter..".txt", "wb");
    saveHandle:write(psdRead);
    saveHandle:close();
    Counter = Counter + 1;
    else
    break;
    end
end


pdfOpen:close();



این کد رو هم برای چسبوندن دوباره برای ایجاد فایل واحد از تیکه هایی که قبلا ایجاد کردین :

کد:
[FONT=Tahoma]openTxt = _SourceFolder.."\\New folder\\SaveCodeLine";[/FONT]
[FONT=Tahoma]savePdf = _SourceFolder.."\\MyPdf.pdf";[/FONT]
[FONT=Tahoma]
[/FONT]
[FONT=Tahoma]for i=1,5 do[/FONT]
[FONT=Tahoma]openHandle = io.open(openTxt..i..".txt", "rb");[/FONT]
[FONT=Tahoma]textContain = openHandle:read("*a");[/FONT]
[FONT=Tahoma]
[/FONT]
[FONT=Tahoma]    pdfHandel = io.open(savePdf, "ab");[/FONT]
[FONT=Tahoma]    pdfHandel:write(textContain);[/FONT]
[FONT=Tahoma]    pdfHandel:close();[/FONT]
[FONT=Tahoma]--openHandle:write("salam   1");[/FONT]
[FONT=Tahoma]
[/FONT]
[FONT=Tahoma]openHandle:close();[/FONT]
[FONT=Tahoma]end[/FONT]
پارامترهای توابع و همینطور مسیر فایل را و حتی الگوریتم رو طبق خواسته تون تغییر بدین

این کد میتونه هر فایلی در هر حجمی را تیکه کنه


حالا میدونین دیگه . میتونین روی هر تیکه از فایل ، انکد خاص خودتون رو داشته باشین با توابع Crypto (البته هدف از تیکه کردن فایل ، انکد کردن شون نیست)
فایل های تیکه شده رو (اگه فیلم و ویدئویی و از این دست باشه باشه نه exe و اینا) اگه با فرمت خودش ذخیره کنیم ، میشه جداگانه هم اجرا کرد.
راستی اینم بگم که البته توی کد دوم (وصل کردن فایل ها) ، کدی که من گذاشتم ، خوب تعداد فایل هایی که تیکه کردم رو میدونستم و 5 تا بود . واسه همین توی حلقه ی 5 تایی گذاشتم . شما باید به تعداد تیکه های فایل تون این حلقه را بزارین

چقد دنبال تیکه کردن فایل بودم:green: الگوریتم به این چندان سادگی را نمیدونم چرا قبلا یادم نیومد:)

 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نکته درباره File i\o :

اول اینکه وقتی کلا خط به خط میخونیم و ذخیره میکنیم اطلاعات ذخیره شده خراب از آب درمیاد ! حالا چه با تابع file:lines() یا با تابع حتی file:read("*l"); فقط باید یا کل فایل را یکجا بخونیم و توی متغییر بریزیم و یا اگه فایل حجیم هست (بالای 200 مگ) و داخل متغییر جا نمیشه ، باید تعداد کاراکتری که میخونیم رو با استفاده از تابع file:read و نوشتن تعداد کاراکترهای مورد نیاز در آرگومان این تابع (نوشتن شماره) و قرار دادن در حلقه while ، به همون تعداد از کاراکترهای اون فایل را بخونیم و توی متغییر ذخیره و توی فایل جداگانه ذخیره کنیم (چرا خوندن خط به خط جواب نمیده ، نمیدونم)

دوم اینکه میشه اطلاعات فایل های باینری رو داخل آرایه ریخت اما وقتی میخوایم آرایه ها را به هم متصل کنیم چون یا بصورت دستی مجبوریم یه رشته ی خالی را برای مقدار ذخیره ی خونه های قبلی آرایه برای جسبوندن استفاده کنیم ، و وقتی هم که به رشته ی حاوی اطلاعات باینری ، کوچیک ترین چیز و یا رشته و یا کاراکتری اضافه کنیم (حتی اگه رشته ی خالی که "" هست رو اضافه کنیم) ساختار باینری و اطلاعاتش کاملا به هم میریزه بنابراین نمیشه اطلاعاتی که داخل آرایه هست رو توی خروجی فایلی ذخیره کنیم (ذخیره میشه ولی اطلاعات آرایه ی ذخیره شده ، اشتباه هست و فایل نهایی ارور میده) و یا اینکه برای اتصال اعضای آرایه از تابع Table.Concat (برای اتوپلی) و یا تابع table.concat (برای لوا) استفاده میکنیمم که هردوی این توابع در آرگومان دوم شون حداقل رشته ی خالی میگیرن برای جدا کردن اعضای آرایه و چون گفته شد که رشته ی حتی اگه هم خالی باشه باعث به هم ریختن اطلاعات رشته ی باینری میشه ، این روش هم نمیشه بنابراین تا جایی که میدونم ، اطلاعات داخل آرایه رو نمیشه به عنوان اطلاعات درست باینری ذخیره کرد.
البته اطلاعات باینری ذخیره شده در آرایه (اگه با تابع file:read() باشه برای اطلاعات باینری (برای اطمینان از این تاب استفاده کنین)) ، درست هست ولی فقط ذخیره نمیتونیم کنیم اطلاعات آرایه رو داخل فایل

سوم اینکه بنابراین فقط اطلاعات فایل های باینری رو میشه بصورت مستقیم ذخیره کرد یعنی اطلاعات فایل را بخونیم و داخل فایل دیگه ذخیره کنیم یا اینکه این اطلاعات باینری رو داخل متغییری ذخیره و بعد داخل فایل دیگه بصورت باینری ذخیره کنیم . البته اگه فایل بزرگ باشه ، همه ی اطلاعات داخل متغییر جا نمیشن و ممکنه ارور بده که در این صورت با شماره دادن در آرگومان تابع file:read() ، به تعداد همون شماره ، کاراکتر رو میخونه یعنی اطلاعات فایل تیکه میشه و حالا این متغییر را که حاوی بخشی از اطلاعات اون فایل بزرگ (فایل مبدا) هست را در یک فایل دیگه میشه ذخیره کرد که مشخصه داخل حلقه میتونیم به تعدادی که دلمون میخواد تیکه کنیم
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 33


قسمت 33 => مباحث تکمیلی شی گرایی ؛ کار با توابع فایل File I\O در لوا و برش فایل ها و ادغام آنها ؛ استفاده از garbagcollector برای آزادسازی رم از متغییرها و آرایه ها (به مدت 4:5 دقیقه و حجم 317 مگابایت)
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
بفرمایید بچه ها تبدیل به تابع کردم که کار کردن باهاش راحت هه :
برای تیکه کردن و برش فایل :

کد:
[FONT=Tahoma]function SpliteFile(SourceFile, DestinationFileSplited, CharacterSpliteCount, FileBinary)[/FONT]
[FONT=Tahoma]    if (FileBinary~=nil and (FileBinary=="" or FileBinary=="text" or FileBinary=="Text" or FileBinary=="t" or FileBinary=="T")) then[/FONT]
[FONT=Tahoma]    FileBinary = "";[/FONT]
[FONT=Tahoma]    else[/FONT]
[FONT=Tahoma]    FileBinary = "b";[/FONT]
[FONT=Tahoma]    end[/FONT]


[FONT=Tahoma]local openForReadHandle, err = io.open(SourceFile, "r"..FileBinary);[/FONT]
[FONT=Tahoma]    if (openForReadHandle==nil) then[/FONT]
[FONT=Tahoma]    return nil, err;[/FONT]
[FONT=Tahoma]    end[/FONT]
[FONT=Tahoma]local destinationSplite = String.SplitPath(DestinationFileSplited);[/FONT]
[FONT=Tahoma]    if (destinationSplite==nil or destinationSplite.Drive=="" or destinationSplite.Folder=="" or destinationSplite.Filename=="" or destinationSplite.Extension=="") then[/FONT]
[FONT=Tahoma]    return nil;[/FONT]
[FONT=Tahoma]    end[/FONT]
[FONT=Tahoma]local destinationFileNameInitialize = destinationSplite.Drive..destinationSplite.Folder..destinationSplite.Filename;[/FONT]
[FONT=Tahoma]local splitedAllFilesPath = {};[/FONT]
[FONT=Tahoma]Counter = 1;[/FONT]


[FONT=Tahoma]    while (true) do[/FONT]
[FONT=Tahoma]    local readContent = openForReadHandle:read(CharacterSpliteCount);[/FONT]
[FONT=Tahoma]        if (readContent~=nil) then[/FONT]
[FONT=Tahoma]        destinationFilePath = destinationFileNameInitialize..Counter..destinationSplite.Extension;[/FONT]
[FONT=Tahoma]        local openForSaveHandle, err = io.open(destinationFilePath, "w"..FileBinary);[/FONT]
[FONT=Tahoma]            if (openForSaveHandle==nil) then[/FONT]
[FONT=Tahoma]            readContent = nil;[/FONT]
[FONT=Tahoma]            collectgarbage();[/FONT]
[FONT=Tahoma]            return nil, err;[/FONT]
[FONT=Tahoma]            end[/FONT]

[FONT=Tahoma]        openForSaveHandle:write(readContent);[/FONT]

[FONT=Tahoma]        openForSaveHandle:close();[/FONT]
[FONT=Tahoma]        readContent = nil;[/FONT]
[FONT=Tahoma]        collectgarbage();[/FONT]
[FONT=Tahoma]        splitedAllFilesPath[Counter] = destinationFilePath;[/FONT]
[FONT=Tahoma]        Counter = Counter + 1;[/FONT]
[FONT=Tahoma]        else[/FONT]
[FONT=Tahoma]        break;[/FONT]
[FONT=Tahoma]        end[/FONT]
[FONT=Tahoma]    end[/FONT]
[FONT=Tahoma]openForReadHandle:close();[/FONT]
[FONT=Tahoma]readContent = nil;[/FONT]
[FONT=Tahoma]collectgarbage();[/FONT]
[FONT=Tahoma]return splitedAllFilesPath;[/FONT]
[FONT=Tahoma]end[/FONT]

توضیحات :

کد:
[FONT=Tahoma]--table  SpliteFile(string SourceFile, string DestinationFileSplited, number CharacterSpliteCount [, string FileBinary]); => resault : table  SplitedFilesPath[/FONT]

تابع SpliteFile :

آرگومان ها :
اولین ورودی (SourceFile) رشته ای هست از مسیر کامل فایلی که میخواین برش بدین (همراه نام و پسوند فایل)
دومین ورودی (DestinationFileSplited) رشته ای هست از مسیر کامل فایل که میخواین تیکه بشه (همراه نام و پسوند فایل) . نکته اینکه نام فایل خودش شماره گذاری میشه اتوماتیک بعد از بریده شدن
*** سومین ورودی (CharacterSpliteCount) عدد هست که تعداد کاراکترهایی که توی هر فایل باید نوشته بشه رو بهش میدین . اینکه بر اساس حجم داده شه ، خودتون جداگانه محاسبه کنین که هر کاراکتر که 8 بیت اشغال میکنه ، این عدد رو چند باید بدین تا به اندازه ی حجم مورد نظرتون بریده شه . فقط اینکه هر 160 میلیون (160000000) کاراکتر ، حجم 152 مگابایت میشه یعنی آرگومان سوم تون رو 160000000 بدین ، هر قسمت از فایل مورد نظرتون که تیکه شد ، 152 مگابایت میشه . و اینکه این عدد یعنی حجم هر فایل اگه بزرگتر باشه ، نوشتن فایل ها سریعتر انجام میشه و برنامه زودتر عمل اش رو انجام میده
*** تذکر مهم : سعی کنین این عدد یعنی سومین ورودی رو بزرگتر از 100 میلیون ندین چون متغییرهای لوا مثل سی شارپ نیست که ظرفیت اش تا اندازه ای که رم طرف جواب داد ، جا بشه یعنی متغییرهای لوا (حداقل نسخه 5.1) ظرفیت محدودی دارن و بیشتر از این احتمال جا نشدن همه ی کاراکترها توشون هست و اگه جا نشن ، ارور میدن که عملیات کنسل میشه . با این حال تا 200 میلیون رو که تست کردم مشکلی نداشت اما بیشتر از این ارور میداد . کلا پیشنهاد من اینه که 100 تا 150 میلیون بیشتر ندین که در این صورت ، تقریبا هر تیکه از فایل 90 تا 140 مگابایت میشه
هر چی این عدد بیشتر بشه مشخصه که متغییر باید توش بیشتر جا بشه و بنابراین نیاز به رم بیشتر میشه (200 میلیون کاراکتر اگه بدین فکر کنم حداقل 2 تا 4 گیگ رم خالی نیاز داشته باشه)
دقت کنین که شما ممکنه تا 300 میلیون هم برای این عدد بدین و موقع برش دادن مشکلی پیش نیاد ولی موقع ادغام کردن ، مشکل ایجاد میشه پس هر عددی که دادین ، بعدش ادغام کنین فایل را ببینین مشکلی پیش نیاد و اگه مشکل Memory Not Enough داد ، این عدد رو کم کنین . البته همونطور که گفته شد باید برای کار با فایل ها ، حافظه ی خالی در رم طرف رو چک کنین که به اندازه ی کافی فضای خالی داشته باشه که این مقدار کاراکتر (برای 200 میلیون ،2 گیگ رم خالی فکر کنم حداقل بخواد) توش جا بشه
*** کلا 150 تا 170 میلیون احتمالش خیلی کمه که ارور بده و هر چی عدد رو کمتر کنین (البته به رم خالی طرف هم بستگی داره) احتمال ارورش هنوز کم و کمتر میشه ولی طرف اگه هر چقدر رم خالی داشته باشه (مثلا 13 گیگ) ، بخاطر ظرفیت محدود متغییرهای لوا و همینطور 32 بیتی بودن اتوپلی (و در نتیجه 32 بیتی بودن پروژه مون) بیشتر از 200 میلیون کاراکتر توی متغییرمون جا نمیشه
چهارمین ورودی (FileBinary) که اختیاری هست و رشته ای هست که مشخص میکنه فایل مورد نظر باینری هست یا نه . 99 درصد فایل ها یعنی فایل هایی بجز فایل های txt ای که خودمون مینویسیم (نه اینکه هر فایلی که پسوند txt داره ، باینری نباشه ها) (فایل word و pdf منظورم نیست ها) که باینری نیستن ، بقیه یعنی همون 99 درصد فایل ها باینری هستن . یعنی فایل های exe و pdf و word و وییدئو و تصویر و ... همه شون باینری هستن . اگه فایل مورد نظرتون ، فایل باینری هست ، لازم نیست اصلا این آرگومان رو پر کنین و لازم نیست اصلا هیچ چی بدین (پر نکردن یا دادن nil فرقی ندارن با هم . فقط دقت کنید که nil دادن با رشته ی خالی یعنی "" دادن فرق داره) . اگه هم فایل تون باینری نیست ، فقط کافیه رشته ی خالی یا رشته ی "t" یا "text" بدین در این آرگومان


خروجی تابع :
یک آرایه (splitedAllFilesPath) که مسیر کامل تک تک فایل های تیکه و برش داده شده هست رو برمیگردونه . اگه ارور داده شه ، تابع nil رو در اولین متغییر و در صورتی که مشکل از تابع Open باشه ، پیام ارور رو بصورت رشته برمیگردونه.


*** تذکر : بعد از اجرای این تابع یا تابع پایین ، برای اینکه متغییرهای محلی تابع ، فضای اشغال شده شون از رم پاک شه ، از تابع collectgarbage() بدون ورودی استفاده کنین




برای ادغام فایل های بریده شده در یک فایل واحد :


کد:
[FONT=Tahoma]function MergeFiles(SplitedFilesPath, DestinationFileMerge, FileBinary)[/FONT]
[FONT=Tahoma]    if (FileBinary~=nil and (FileBinary=="" or FileBinary=="text" or FileBinary=="Text" or FileBinary=="t" or FileBinary=="T")) then[/FONT]
[FONT=Tahoma]    FileBinary = "";[/FONT]
[FONT=Tahoma]    else[/FONT]
[FONT=Tahoma]    FileBinary = "b";[/FONT]
[FONT=Tahoma]    end[/FONT]


[FONT=Tahoma]local openForSaveHandle, err = io.open(DestinationFileMerge, "a"..FileBinary);[/FONT]
[FONT=Tahoma]    if (openForSaveHandle==nil) then[/FONT]
[FONT=Tahoma]    return nil, err[/FONT]
[FONT=Tahoma]    end[/FONT]


[FONT=Tahoma]    for i=1,#SplitedFilesPath do[/FONT]
[FONT=Tahoma]    local openForReadHandle, err = io.open(SplitedFilesPath[i], "r"..FileBinary);[/FONT]
[FONT=Tahoma]        if (openForReadHandle==nil) then[/FONT]
[FONT=Tahoma]        return nil, err[/FONT]
[FONT=Tahoma]        end[/FONT]

[FONT=Tahoma]    readContent = openForReadHandle:read("*a");[/FONT]
[FONT=Tahoma]    openForSaveHandle:write(readContent);[/FONT]

[FONT=Tahoma]    openForReadHandle:close();[/FONT]
[FONT=Tahoma]    end[/FONT]


[FONT=Tahoma]openForSaveHandle:close();[/FONT]
[FONT=Tahoma]readContent = nil;[/FONT]
[FONT=Tahoma]collectgarbage();[/FONT]
[FONT=Tahoma]end[/FONT]

توضیحات :


کد:
[FONT=Tahoma]--MergeFiles(table mySplitedFilesPath, string DestinationFileMerge [, string FileBinary])[/FONT]

تابع MergeFiles :

آرگومان ها :
ورودی اول (SplitedFilesPath) ، یک آرایه ی رشته ای حاوی مسیر کامل تمام فایل های مبدا که همون فایل های تیکه و جدا شده هست ، هست (خروجی تابع SpliteFile در صورت موفقیت ، همچین آرایه ای رو برمیگردونه) (همراه نام و پسوند دونه دونه ی فایل های جدا شده)
ورودی دوم (DestinationFileMerge) رشته ای حاوی مسیر کامل فایل مقصد یا فایل واحد ای که میخواین ادغام کنین (همراه نام و پسوند فایل)
ورودی سوم (FileBinary) که همون ورودی آخر تابع SpliteFile هست که در بالا توضیح داده شد و اختیاری هست (بصورت پیش فرض برای فایل های باینری هه)




*** نکته : فایل های تیکه شده ، بسته به اینکه چه نوع فایل و با چه پسوندی باشن ، میتونین با اونکه جدا هم هستن اجرا بشن یا نه مثلا اگه فایل های ویدئویی با پسوند ویدئویی رو بصورت تیکه شده ذخیره کنین ، هر تیکه میشه مستقل اجرا بشه ولی اگه با پسوند ویدئویی ذخیره نکین ، مثل حالت عادی چون پسوندش فرق داره ، ممکنه توسط بعضی از پلیرها اجرا نشه ولی محتوای فایل درست هست حالا میخواد با هر پسوندی باشه (البته اگه موقع برش فایل مشکلی پیش نیاد که در بالا توضیح داده شد) . اما مشخص هست اگه فایل هایی مثل فایل های exe برش داده بشن هر تیکه از فایل های برش داده شده شون اجرا نمیشه و معنا نداره (حتی اگه همه ی تیکه هاش با پسوند exe ذخیره شن) تا زمانی که دوباره این فایل های بریده شده ی exe را در یک فایل واحد دیگه ادغام کنین که اون وقت قابل اجراست



مثال :

کد:
[FONT=Tahoma]mySplitedFilesPath = SpliteFile("G:\\Tolo 6\\narm afzar\\Other Software\\Virtual Tools\\VMware Workstation Pro 12.0.0 Build 2985596\\VMware Workstation Pro 12.exe", _SourceFolder.."\\New folder\\VMware Workstation Pro .exe", 100000000);[/FONT]
[FONT=Tahoma]if (mySplitedFilesPath~=nil) then[/FONT]
[FONT=Tahoma]MergeFiles(mySplitedFilesPath, _SourceFolder.."\\VMware Workstation Pro .exe");[/FONT]
[FONT=Tahoma]end[/FONT]
[FONT=Tahoma]collectgarbage();[/FONT]
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بفرمایید بچه ها اینم سورس اش
فقط چون روی کدها وقت نزاشتم ، چند تا مورد را باید رعایت کنین تا مشکلی پیش نیاد :
اول اینکه دکمه ی Merge را برای هر کدوم فقط یک بار بزنین وگرنه هر بار فایل را دوباره در ادامه اش مینویسه که هم باعث اجرا نشدن فایل میشه (در اغلب موارد) و هم حجیم شدنش میشه
دوم اینکه دو دکمه ی Merge مختلف رو پشت سر هم نزنین یعنی این طوری نکنین که MP3 Merge رو زدین ، بعدش pdf Merge رو بزنین . یعنی اول باید یک دکمه ی Splite رو بزنین و بعد دکمه ی Merge مربوط به اون رو بزنین
چون خودتون خواستین چند تا فایل mp3 و pdf و exe با پروژه هست که باعث افزایش حجم پروژه شد
پروژه رو چون داخل چند انجمن میخوام بزارم واسه همین توی این انجمن بطور خواص آپلود نکردم


از اینجا دانلود کنین با حجم 30 مگابایت
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دانلود آموزش AMS قسمت 34

قسمت 34 => اولین قسمت آموزش دیتابیس (توضیح پایگاه داده SQLite و جدول هاو فیلدها و رکوردها ، ساختار و چگونگی ذخیره کردن در اون . طراحی یه دیتابیس بصورت ویژال (دقت کنید این قسمت بصورت کدنویسی با دیتابیس کار نشده) ؛ و کاربرد return در توابع و رویدادهای اتوپلی) (به مدت 3:46 دقیقه و حجم 194 مگابایت)
 
آخرین ویرایش:

جدیدترین ارسال ها

بالا