درس دوازدهم: نوشتن توابع ساده
درس دوازدهم: نوشتن توابع ساده
12-1 مقدمه
همانطور که قبلا هم اشاره شد، ویژوال بیسیک یک زبان شی گراست. اگر با مفهوم شی گرایی آشنا نیستید نگران نباشید که در دروس آتی به آن هم خواهیم پرداخت. اما فعلا فقط دو نکته را بدانید. اول اینکه هرچه تاکنون یاد گرفتید، تعدادی از مفاهیم اولیه ی پایه برای ساخت برنامه های بسیار ساده می باشد و اصلا به تکنیکهای OOP و اصول اولیه ی طراحی برنامه های پیچیده اشاره نکرده ایم. دوم اینکه در این درس هم به یادگیری نوشتن تابع ساده می پردازیم که از چهارچوب OOP و تکنیک های پیشرفته تر خارج است.
توجه داشته باشید که یادگیری این مفاهیم پایه قبل از پرداختن به تکنیکهای پیچیده تر برنامه نویسی مدرن، الزامی و حیاتی ست.
اما تابع چیست؟
توابع قطعه کدهایی هستند که اجرا نمیشوند مگر آنکه آنها را صدا بزنیم. به عبارت دیگر توابع بعد از نوشته شدن، باید در جایی از برنامه فراخوانی شوند تا اجرا شوند. و این فراخوانی میتواند در هرجای برنامه به صورت یک بار یا دفعات بسیار زیادی انجام شود. و این دقیقا بزرگترین فایده ی توابع است. تابع را میتوان یک بار نوشت و هزاران بار استفاده کرد. از مزایای توابع میتوان به موارد زیر اشاره کرد:
- حجم کد را کاهش میدهد
- حجم برنامه را کاهش میدهد
- سرعت برنامه را بالا میبرد
- خوانایی برنامه را بهتر میکند
- اشکال یابی را آسان تر میکند
- باعث صرفه جویی در زمان میشود
تا به اکنون با بسیاری توابع پیش فرض ویژوال استدیو آشنا شده اید. در درسهای گذشته از توابعی مانند ()LEN(), MID(), SIN و غیره استفاده کرده ایم. اما در این در میخواهیم خودمان توابع مورد نیاز خود را بنویسیم.
12-2 سینتکس نوشتن تابع
12-2-1 تعریف تابع
سینتکس کامل نوشتن تابع به صورت زیر است:
Public Function functionName (arg1 as dataType1, arg2 as dataType2, … ) [As dataType]
Statements
[Return variable]
End Fucntion
در سینتکس بالا با کلمه های کلیدی Public Function کد را آغاز و در مقابل آن نامی را قرار میدهیم. سپس مقابل نام یک پرانتز باز و بسته میگذاریم و داخل آنها در صورت نیاز متغیر هایی که باید وارد تابعمان شوند را تعریف میکنیم و بلاک را با عبارت کلیدی End Function می بندیم. تمام کدهای خود را در بین این دو خط می نویسیم. محتویات داخل کروشه ها اختیاری ست و در ادامه به توضیح آنان میپردازیم.
نکته ی 1: کلمه ی کلیدی Public یعنی این تابع برای تمام برنامه و کل کلاسها (در دروس بعدی به کلاسها خواهیم پرداخت) در دسترس است. در صورتی که نمیخواهید این تابع برای باقی کلاسها هم در دسترس باشد به جای Public از کلمه ی کلیدی Private استفاده کنید.
نکته ی 2: توابعی که مینویسید، میتوانند ورودی بگیرند و یا هیچ ورودی ای نپذیرند. برای مثال توابعی از پیش تعریف شده مثل ()LEN را به یاد آورید. این تابع در داخل پرانتزها یک متغیر حاوی رشته ی حروف یا یک رشته ی حروف به صورت مستقیم میپذیرد و طول آن را بر میگرداند. چنین تابعی ورودی میپذیرد. اگر میخواهید تابعی بنویسید که یک یا چند ورودی بپذیرد و پاسخی که بر میگرداند بر حسب آن ورودی ها باشد، باید در هنگام تعریف تابع داخل پرانتز ها متغیرهای مورد نیاز را تعریف کنید. وگرنه آن را خالی بگذارید.
12-2-2 صدا زدن و استفاده از تابع
برای صدا زدن و فراخوانی تابع اگر تابع از نوعی است که ورودی نمیپذیرد، کافی ست نام آن را نوشته و مقابل آن دو پرانتز باز و بسته ی خالی بگذارید. اما اگر تابع ورودی میپذیرد، داخل پرانتز ها ورودی ها را قرار دهید. ورودی ها را با یک کاما از هم جدا کنید.
مثال :
Public Class Form1 Public Function Alert() MsgBox("This message is getting displayed from inside a function !!!") End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Alert() End Sub End Class
در مثال بالا تابعی نوشتیم که هیچ ورودی ای نمیپذیرد. داخل کلاس اصلی، تابع Alert را نوشتیم و سپس در رخداد کلیک دکمه ی Button1 آن را فراخوانی کردیم. برای فراخوانی یک تابع ساده نیز کافی ست نام آن را بنویسید و مقابل ان یک جفت پرانتز باز و بسته قرار دهید. خواهید دید که جمله ی "این پیغام از داخل یک تابع نمایش داده میشود" ظاهر خواهد شد. (شکل 1-12 و 2-12)
شکل 1-12
مثال :
Public Class Form1 Public Function Alert(name As String) MsgBox("Hello Mr. " & name & "! ") End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Alert(InputBox("Enter your name!")) End Sub End Class
در مثال بالا تابعی نوشتیم که یک ورودی از جنس رشته ای میپذیرد. موقع فراخوانی تابع در رویداد کلیک دکمه ی Button1 ، با تابع InputBox یک ورودی از کاربر گرفتیم و آن را مستقیم داخل تابع قرار دادیم. تابع ما نامی که کاربر وارد کرده را با پیغام سلام ترکیب و نمایش میدهد. (شکل 2-12)
شکل 2-12
12-3 برگرداندن داده (تابع با خروجی)
در دو مثال بالا، هر دو تابع، (چه تابعی که ورودی میپذیرفت و چه تابعی که ورودی نداشت) عملیات نمایش پیغام را از داخل خودشان انجام میدادند و مقداری بر نمیگرداندند. یعنی دو تابع مذکور بدون خروجی بودند.
حال دوباره تابع پیشفرض ()LEN را به یاد آورید. اگر خاطرتان باشد این تابع بعد از پذیرفتن یک رشته یا متغیری حاوی یک رشته به عنوان ورودی، طول رشته را بر میگرداند که میتوانستیم آن را در یک متغیر عددی ذخیره یا به صورت مستقیم استفده کنیم. یعنی تابع ()LEN خروجی دارد. حالا ما میخواهیم همین کار را با تابع دست نویس خودمان کنیم. میخواهیم تابعی بنویسیم که به جای اینکه همه کار را خودش انجام دهد، نتیجه را به عنوان خروجی برگرداند. مثلا دو عدد گرفته و آنها را در هم ضرب و نتیجه را برگرداند. برای برگرداندن داده از تابع دو روش وجود دارد:
12-3-1 برگرداندن داده به صورت مستقیم از تابع
در این روش خود تابع یک متغیر است. یعنی بعد از تعریف تابع با نام دلخواه، برای آن یک نوع داده مشخص کرده و در داخل تابع، نام خود تابع را به عنوان یک متغیر خروجی استفاده میکنیم. توجه کنید که در این روش متغیری که به عنوان متغیر خروجی استفاده میکنید دقیقا باید همنام تابع باشد. مثلا:
Public Function sum(a As Integer, b As Integer) As Integer sum = a + b End Function
سپس در هنگام فراخوانی تابع میتوانیم از تابع به صورت زیر خروجی بگیریم:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim a As Integer, b As Integer
a = Val(TextBox1.Text)
b = Val(TextBox2.Text) MsgBox(sum(a, b)) End Sub
12-3-2 برگرداندن داده به صورت غیر مستقیم از تابع
در این روش در داخل تابع یک متغیر تعریف میکنیم و آن را به عنوان متغیر خروجی استفاده میکنیم. اما برای گرفتن خروجی از آن حتما باید از کلمه ی کلیدی return استفاده کنیم. مثلا:
Public Function sum(a As Integer, b As Integer) Dim result As Integer result = a + b Return result End Function
سپس در هنگام فراخوانی تابع به صورت زیر از آن خروجی میگیریم.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim a As Integer, b As Integer a = Val(TextBox1.Text) b = Val(TextBox2.Text) MsgBox(sum(a, b)) End Sub
نکته ی 3: روش دوم به علت مصرف اضافی حافظه بابت تعریف یک متغیر اضافی چندان معقول نیست و توصیه میکنم همیشه تا جای ممکن از روش اول استفاده کنید.
12-4 روشهای دسترسی تابع به داده ی ورودی byVal و byRef
همانطور که دیدیم در نوشتن تابع میتوانیم تابع را طوری بنویسیم که داده یا داده هایی را به عنوان ورودی بپذیرد. همچنین میتوان تابعی نوشت که هیچ ورودی ندارد. در اینجا با توابعی بدون ورودی کاری نداریم. اما به توابعی که ورودی میپذیرند توجه کنید. مثلا تابعی داریم که یک عدد به عنوان ورودی میپذیرد. آن را به توان دو میبرد و مقدار حاصل را به عنوان خروجی برمیگرداند. وقتی عددی که میخواهیم به توان دو برسانیم به تابع خود میدهیم چه اتفاقی برای آن عدد می افتد؟ عدد ورودی بعد از عملیات سالم میماند یا تغییر میکند؟ این به نوع دسترسی تعیین شده برای تابع بستگی دارد. به طور کلی دو روش برای صدا زدن تابع وجود دارد. دسترسی با رفرنس و دسترسی با مقدار:
12-4-1 دسترسی ByVal
دسترسی با مقدار یعنی تابع به اصل دیتا دسترسی ندارد و فقط یک کپی از دیتا را در اختیار دارد و این کپی بعد از پایان عملیات از بین میرود. در این روش تابع هیچ تغییری نمی تواند در داده ها ایجاد کند. برای فعال کردن این روش در هنگام نوشتن تابع و موقع تعریف متغیرهای ورودی برای آن، قبل از نام هر متغیر از کلمه ی کلیدی ByVal استفاده کنید. مثال:
Public Class Form1 Public Function example(ByVal x As Integer) x = Math.Sqrt(x) Return x End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim x As Integer = Val(InputBox("Enter a num")) MsgBox("جذر عددی که وارد کردید برابر است با = " & example(x) & vbNewLine & "مقدار قبلی عددی که وارد کردید برابر است با = " & x, MsgBoxStyle.Information + MessageBoxOptions.RightAlign + vbOKOnly + MessageBoxOptions.RtlReading, "دسترسی با مقدار") End Sub End Class
در مثال بالا تابعی نوشتیم که یک عدد را به عنوان ورودی با روش دسترسی با رفرنس میپذیرد و جذر آن را حساب میکند. ما این کار را طوری انجام دادیم که تابع در صورت توانایی خود عدد ورودی را هم تغییر دهد. سپس در رویداد کلیک دکمه ی Button1 یک پیغام چاپ کردیم و خط اول این پیغام پاسخ جذر را نشان میدهد و خط دوم این پیغام مقدار فعلی عدد اولیه را نمایش میدهد. میبینید که عدد اصلی هیچ تغییری نکرده و از آنجایی که تابع دسترسی به داده نداشته نتوانسته در آن تغییری دهد و عدد همان مقداری ست که کاربر وارد کرده بود. خروجی را در شکل 3-12 میبینید.
شکل 3-12
12-4-2 دسترسی ByRef
دسترسی با رفرنس یعنی تابع به اصل دیتا دسترسی دارد و در صورت نیاز میتواند در داده یا داده ها تغییراتی بدهد. برای فعال کردن این روش در هنگام نوشتن تابع و موقع تعریف متغیر های ورودی برای آن، قبل از نام هر متغیر از کلمه ی کلیدی ByRef استفاده کنید. مثال:
Public Class Form1 Public Function example(ByRef x As Integer) x = Math.Sqrt(x) Return x End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim x As Integer = Val(InputBox("Enter a num")) MsgBox("جذر عددی که وارد کردید برابر است با = " & example(x) & vbNewLine & "مقدار قبلی عددی که وارد کردید برابر است با = " & x, MsgBoxStyle.Information + MessageBoxOptions.RightAlign + vbOKOnly + MessageBoxOptions.RtlReading, "دسترسی با رفرنس") End Sub End Class
در مثال بالا تابعی نوشتیم که یک عدد را به عنوان ورودی با روش دسترسی با رفرنس میپذیرد و جذر آن را حساب میکند. ما این کار را طوری انجام دادیم که تابع در صورت توانایی خود عدد ورودی را هم تغییر دهد. سپس در رویداد کلیک دکمه ی Button1 یک پیغام چاپ کردیم و خط اول این پیغام پاسخ جذر را نشان میدهد و خط دوم این پیغام مقدار فعلی عدد اولیه را نمایش میدهد. میبینید که اینبار عدد اصلی تغییر کرده است. خروجی را در شکل 4-12 میبینید.
شکل 4-12
نکته ی 4: باید توجه داشت اگر نوع دسترسی به دیتا را در هنگام تعریف تابع ذکر نکنید، چنانکه ما در اوایل این درس نوع دسترسی byVal یا byRef را مشخص نکردیم، آنگاه دسترسی به صورت پیشفرض ByVal خواهد بود. به همین خاطر هرموقع خواستید دسترسی با مقدار را برای تابع خود معین کنید، هم میتوانید از کلمه ی کلیدی ByVal استفاده کنید و هم میتوانید جای آن را خالی بگذارید. ولی استفاده از کلمه ی کلیدی ByRef برای نوع دسترسی با رفرنس الزامی میباشد.
نکته ی 5: از روش دسترسی با رفرنس میتوان به عنوان تکنیکی برای گرفتن بیش از یک خروجی از تابع استفاده کرد.
تمرین : برنامه ای بنویسید که دو عدد را از ورودی های TextBox دریافت و با استفاده از تابعی عدد اولی را به توان دومی برساند و نتیجه را در یک لیبل نشان دهد.