توابع در کاتلین | بررسی نحوه تعریف و انواع توابع در زبان Kotlin

توابع در کاتلین | بررسی نحوه تعریف و انواع توابع در زبان Kotlin

نوشته شده توسط: تیم فنی نیک آموز
تاریخ انتشار: ۱۱ تیر ۱۴۰۳
آخرین بروزرسانی: 13 تیر 1403
زمان مطالعه: 14 دقیقه
۵
(۲)

توابع در کاتلین، مثل ابزارهای چندکاره در جعبه ابزار برنامه‌نویسی شما هستند. آن‌ها بخش‌هایی از کدتان هستند که قابلیت استفاده مجدد دارند. این بخش‌ها هرجای برنامه ممکن است فراخوانی شوند و وظایف مشخصی را انجام دهند. زبان کاتلین، به‌عنوان یکی از محبوب‌ترین زبان‌های برنامه‌نویسی، اهمیت ویژه‌ای برای توابع درنظر گرفته است. هر برنامه‌ کاتلین، با یک تابع fun main آغاز می‌شود. این موضوع نشان‌دهنده نقش کلیدی توابع در ساختار و سازماندهی برنامه‌های کاتلین است. در این مقاله، با نحوه تعریف و انواع توابع در زبان برنامه‌نویسی کاتلین آشنا خواهید شد.

آموزش کاتلین برای برنامه نویسان اندروید نیک آموز

توابع در کاتلین چیست؟

توابع بلوک‌‌های مجزا از کد هستند که وظایف مشخصی انجام می‌دهند و شما می‌توانید هرجای برنامه از آن استفاده کنید. توابع در کاتلین با استفاده از کلمه «fun» تعریف می‌شود. با این کار، می‌توانید کدهای خود را منظم‌تر کرده و برای استفاده از وظایف تکراری، آن‌ها را به‌کار ببرید. در ادامه، نحوه ایجاد و تعریف توابع را بررسی می‌کنیم.

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

پس از به‌کار بردن کلمه «fun» در کاتلین، لیست پارامترها و نوع داده‌ای را که تابع برمی‌گرداند، مشخص می‌کنیم. سینتکس یک تابع در کاتلین به‌صورت زیر است:

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

برای تعریف یک تابع در Kotlin از کلمه کلیدی «fun» استفاده می‌کنیم. سپس نام تابع را می‌نویسیم. یک جفت پرانتز و در نهایت یک آکولاد باز و بسته نیز قرار می‌دهیم. دستورات و کدهایی که می‌خواهیم تابع اجرا کند، داخل آکولادها نوشته می‌شوند.

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

 

fun main
()
{

    println
(
"Happy Birthday, Rover!"
)

    println
(
"You are now 5 years old!"
)

}

 

بعد از تابع ()‌main، یک تابع جدید به نام birthdayGreeting تعریف کنید. نحوه نوشتن این تابع مشابه تابع main در بالا است:

 

fun main
()
{
    println
(
"Happy Birthday, Rover!"
)
    println
(
"You are now 5 years old!"
)
}
fun birthdayGreeting
()
{
}

 

حالا دو دستور println را از داخل تابع main برداشته و داخل بخش تابع birthdayGreeting قرار دهید:

 

fun main
()
{
}
fun birthdayGreeting
()
{
    println
(
"Happy Birthday, Rover!"
)
    println
(
"You are now 5 years old!"
)
}

 

در تابع main‌، تابع birthdayGreeting را فراخوانی کنید. کد نهایی شما باید به شکل زیر باشد:

 

fun main
()
{
 
    birthdayGreeting
()
 
}
 
fun birthdayGreeting
()
{
    println
(
"Happy Birthday, Rover!"
)
    println
(
"You are now 5 years old!"
)
 
} 

 

حالا کد خود را اجرا کنید. خروجی شما باید به‌صورت زیر باشد:

 

Happy Birthday, Rover!
You are now 5 years old!

 

پارامترها و مقادیر بازگشتی در توابع کاتلین

توابع در کاتلین اطلاعاتی را به‌عنوان ورودی دریافت می‌کنند که به آن‌ها پارامتر می‌گویند. این پارامترها شبیه مواد اولیه‌ای هستند که به تابع داده می‌شوند تا وظیفه‌اش را به‌درستی انجام دهد. همچنین توابع خروجی‌ نیز دارند که به آن مقدار برگشتی گفته می‌شود.

برای تعریف توابع در کاتلین ، از حالت نگارش پاسکال استفاده می‌شود، یعنی نام: نوع (نام پارامتر و نوع داده‌ای آن). پارامترهای ورودی تابع با کاما ازهم جدا می‌شوند. اگر تابعی هیچ مقداری را برنگرداند، نوع بازگشتی آن Unit درنظر گرفته می‌شود. ذکر نوع بازگشتی برای توابعی که خروجی ندارند، اختیاری است.

 

fun functionName(number1: Int, number2: Int){  
.. .. ..  
}  
.. .. ..  
functionName(value1, value2)  
.. .. ..  

 

یک مثال ساده از تابع پارامتردار در کاتلین

در این مثال، ما یک تابع ساده به نام sum ایجاد می‌کنیم که دو عدد را به‌عنوان ورودی دریافت می‌کند و مجموع آن‌ها را برمی‌گرداند.

 

fun main(args: Array<String>){  
   val result = sum(5, 6)  
    print(result)  
}  
fun sum(number1: Int, number2:Int): Int{  
    val add = number1+number2  
    return add  
}   

 

خروجی آن به‌صورت زیر است:

 

۱۱

 

انواع توابع در کاتلین

در زبان برنامه‌نویسی کاتلین، با دو نوع تابع روبه‌رو هستیم.:

  1. توابع کتابخانه‌ای
  2. توابع تعریف‌شده توسط کاربر

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

کتابخانه استاندارد در کاتلین

کتابخانه استاندارد در کاتلین، مجموعه‌ای غنی از توابع ازپیش‌ساخته‌شده است که در دسترس شما قرار دارند. این توابع در کاتلین به شما امکان می‌دهند بدون نیاز به نوشتن کدهای تکراری و حجیم، کارهای رایج برنامه‌نویسی را انجام دهید.

به‌عنوان مثال، فرض کنید می‌خواهید ریشه دوم عدد ۲۵ را محاسبه کنید. به جای نوشتن کد اختصاصی برای این کار، می‌توانید از تابع sqrt کتابخانه استاندارد استفاده نمایید. این تابع، ریشه دوم عددی را که به‌عنوان ورودی دریافت می‌کند، برمی‌گرداند.

در اینجا، یک نمونه کد برای محاسبه ریشه دوم عدد ۲۵ آورده شده است:

 

 fun main() {
  val number = 25.0
  val result = Math.sqrt(number)
   println("Square root of $number is $result")
}

 

خروجی اجرای این کد به‌صورت زیر خواهد بود:

 

Square root of 25 is 5.0

 

در این کد:

  • sqrt تابعی از کتابخانه استاندارد برای محاسبه ریشه دوم است.
  • println نیز تابعی دیگر از کتابخانه استاندارد است که برای چاپ خروجی روی صفحه نمایش استفاده می‌شود.

تابع ساخته شده توسط کاربر در کاتلین

برخلاف زبان‌هایی مثل جاوا یا اسکالا، در کاتلین برای تعریف تابع نیازی به ساختن یک کلاس نیست. شما می‌توانید به‌راحتی و به‌صورت مستقیم، توابع در کاتلین را در ابتدای کد خود بنویسید.

ساختار کلی یک توابع در کاتلین توسط کاربر 

 

fun fun_name(a: data_type, b: data_type, ......): return_type  {

  // other codes

  return

}

 

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

  • fun: این کلیدواژه به کامپایلر اعلام می‌کند که می‌خواهیم یک تابع تعریف کنیم.
  • fun_name: اسمی که برای تابع خود انتخاب می‌کنید. با این اسم، بعداً تابع را فراخوانی خواهید کرد.
  • data_type: درواقع، (a: data_type , b: data_type , ……) آرگومان‌های ورودی تابع هستند. هر آرگومان، یک نام و یک نوع داده (مثل عدد صحیح یا رشته) دارد. شما می‌توانید چندین آرگومان را با کاما ازهم جدا کنید.
  • return_type: این بخش مشخص می‌کند که تابع شما چه نوع داده‌ای را به‌عنوان خروجی برمی‌گرداند. یک تابع می‌تواند هیچ خروجی نداشته باشد (مثل Unit) یا اینکه مقداری را به‌عنوان خروجی برگرداند. (مثل Int برای عدد صحیح یا String برای متن).
  • {….} : این علامت‌های برابری، بلوک اصلی تابع را مشخص می‌کنند. در این بخش، دستورات و منطق اصلی تابع نوشته می‌شود.

برای مثال، ما یک تابع به نام sum ایجاد می‌کنیم که دو عدد را باهم جمع و نتیجه را چاپ می‌کند.

 

fun main(args: Array<String>){  

    sum()  

    print("code after sum")  

}  

fun sum(){  

    var num1 =5  

    var num2 = 6  

    println("sum = "+(num1+num2))  

}

 

نتیجه به‌صورت زیر خواهد بود:

 

Sum = 11

code after Sum

 

مدیریت خطاها و استثناها در توابع کاتلین

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

مدیریت خطا با استفاده از Either

Either حکم سپر و شمشیر برنامه مقابل خطاهای توابع در کاتلین را دارد. این ابزار قدرتمند، به شما امکان می‌دهد که دو حالت را درنظر بگیرید:

  • حالت موفقیت (Right): زمانی که همه‌چیز طبق برنامه پیش می‌رود و شما به نتیجه دلخواه خود می‌رسید.
  • حالت خطا (Left): زمانی که کابوس خطا ظاهر می‌شود و شما باید با آن روبه‌رو شوید.

Either با ارائه دو نوع خروجی Right برای حالت موفقیت و Left برای حالت خطا، به شما کمک می‌کند تا با ظرافت کامل با خطاها برخورد کنید.

مثال استفاده از Either

فرض کنید می‌خواهید اطلاعات یک کاربر را از پایگاه داده دریافت کنید، اما ممکن است کاربر وجود نداشته باشد یا خطایی در اتصال به پایگاه داده رخ دهد. در این شرایط، می‌توانید از Either برای مدیریت خطاهای توابع در کاتلین به‌صورت زیر استفاده کنید:

 

fun findOrder(id: Int): Either<DomainError, Order> = either {

    if (id < 0) raise(DomainError.OrderNotFound(id))

    Order(id, 1)
}
fun findCustomer(id: Int): Either<DomainError, Customer> = either {

    if (id != 1) raise(DomainError.CustomerNotFound(id))

    Customer(id, "john.doe@mycompany.com")

}

 

مدیریت خطا با سازنده nullable

سازنده nullable در کاتلین به شما این امکان را می‌دهد که براساس نوع خطا، خروجی متفاوتی داشته باشید. این سازنده به شما کمک می‌کند تا با خطاها به روشی هوشمندانه‌تر برخورد کنید:

  • استثناهای بحرانی: برای خطاهای بسیار مهم و خطرناک که باید فوراً به اطلاع کاربر برسند، از پرتاب استثنا (throw) استفاده می‌شود. این کار مثل ترمز شدید در جاده است و به شما می‌گوید که باید سریع اقدام کنید.
  • خطاهای قابل بازیابی: برای خطاهای کم‌اهمیت‌تر که می‌توان آن‌ها را حل کرد، از خروجی null استفاده می‌شود. این کار مثل کاهش سرعت در جاده است و به شما می‌گوید که می‌توانید بعداً به حل مشکل بپردازید.

برای درک بهتر نحوه عملکرد سازنده nullable میان توابع در کاتلین، یک تابع فرضی findOrder تعریف می‌کنیم:

 

fun findOrder(id: Int): Order? = nullable {

    if(id > 0) Order(id) else throw Exception("Order Id must be a positive number")

}

 

در این مثال، تابع findOrder یک شناسه سفارش را به عنوان ورودی دریافت می‌کند و درصورت مثبت بودن شناسه، یک نمونه از کلاس Order را برمی‌گرداند. اگر شناسه سفارش منفی باشد، یک استثنا با پیام «شناسه سفارش باید عدد مثبتی باشد» ارسال می‌کند.

با استفاده از سازنده nullable تابع findOrder را به‌صورت زیر بازنویسی می‌کنیم:

 

val orderId: Int = findOrder(-1)?.id ?: -1

 

Either.catch در مقابل سازنده nullable

برخلاف سازنده ساده nullable در کاتلین، تابع سازنده Either.catch کتابخانه Arrow به‌طور خودکار خطاهای غیرقابل بازیابی را از خطاهای قابل بازیابی تشخیص می‌دهد. بنابراین، نیازی به تعریف یک تابع سازنده جداگانه برای این کار نداریم.

مثالی از ترکیب توابع با Either

فرض کنید می‌خواهیم ابتدا شناسه سفارش را دریافت کنیم، سپس با استفاده از شناسه، اطلاعات مشتری را پیدا کنیم. درنهایتT ایمیل مشتری را بازیابی کنیم. با استفاده از Either.catch ، این کار را به‌صورت زیر انجام می‌دهیم:

 

findOrder(1)

  .flatMap { order ->

    Either.catch { findCustomer(order.customerId) }

  }

  .map { customer -> customer.email }

 

در این مثال، تابع findOrder شناسه سفارش را به‌عنوان Either برمی‌گرداند. سپس، از flatMap برای تبدیل Either به Either دیگر استفاده می‌کنیم. در داخل flatMap ، از Either.catch برای تشخیص خودکار نوع خطا در تابع findCustomer استفاده می‌شود. درنهایت، از map برای بازیابی ایمیل مشتری از Either نهایی استفاده می‌کنیم.

همانطور که می‌بینید، کد بسیار خواناتر و سازمان‌یافته‌تر شده است. با استفاده از توابع map و flatMap می‌توانیم توابع در کاتلین را به‌صورت زنجیره‌ای ترکیب کنیم و درعین حال، خطاها را در هر مرحله مدیریت نماییم. این ویژگی Either به ما امکان می‌دهد تا کدهای پیچیده‌تری بنویسیم و همچنان خوانایی آن را حفظ کنیم.

نکات و بهترین روش های نوشتن توابع در کاتلین

نوشتن توابع در کاتلین به‌صورت صحیح و کارآمد، نقشی کلیدی در خوانایی، سازماندهی و کارایی کد شما دارد. در ادامه، به برخی از نکات برای نوشتن توابع در زبان برنامه‌نویسی کاتلین می‌پردازیم.

  • نام تابع باید به‌طور واضح و گویا، وظیفه‌ای را که انجام می‌دهد، نشان دهد.
  • برای وظایف پیچیده، از توابع کوچک‌تر به‌عنوان توابع کمکی (helper functions) استفاده کنید.
  • از مقادیر پیش‌فرض (default values) برای پارامترها استفاده کنید تا خوانایی کد را افزایش دهید.
  • برای توابع خود، تست‌های واحد (unit tests) بنویسید تا از عملکرد صحیح آن‌ها اطمینان حاصل کنید.

بهترین جایگزین در کاتلین برای حلقه های for

حلقه‌های for ابزار مفیدی در برنامه‌نویسی دستوری هستند؛ اما میان همه توابع در کاتلین ، همیشه بهترین انتخاب نیستند. زمانی که تابعی وجود دارد که کار شما را به‌طور بهتری انجام می‌دهد، بهتر است از آن تابع استفاده کنید. در ادامه، چند جایگزین برای حلقه‌های for را بررسی می‌کنیم. در دستورات زیر، در دو بخش Don’t و DO به شما نشان دادیم چه دستوراتی را به‌جای کدام دستورات استفاده کنید.

دستور repeat

 

// DON'T

fun main() {

 for (i in 0 until 10) {

 println(i)

 }

}

// DO

fun main() {

 repeat(10) {

   println(it)

 }
}

 

دستور forEach

 

// DON'T

fun main() {

  val list = listOf(1, 2, 3, 4, 5, 6)

  for (e in list) {

    println(e)

  }

}

// DO

fun main() {

  listOf(1, 2, 3, 4, 5, 6).forEach {

    println(it)

  }

}

 

دستور map

 

// DON'T

fun main() {

  val list = listOf(1, 2, 3, 4, 5, 6)

  val newList = mutableListOf<Int()

  for (e in list) {

    newList.add(e * e)

  }

}

// DO

fun main() {

  val list = listOf(1, 2, 3, 4, 5, 6)

  val newList = list.map { it * it }

}

 

کار با آبجکت ها در کاتلین به شیوه ای ساده و موثر

میان انواع توابع در کاتلین ، پنج تابع اسکوپی قدرتمند وجود دارند که به شما کمک می‌کنند تا به شکلی تمیز و مؤثر با آبجکت‌ها کار کنید. این توابع عبارتند از: let ،also ،apply ،with و run.

تابع let: عبور از سد مقادیر null

تابع let به شما کمک می‌کند تا با خیال راحت از مقادیر null عبور کنید. زمانی که با مقادیر اختیاری (nullable) سروکار دارید، این تابع بسیار کاربردی است.

 

fun main() {

  val age = readLine()?.toIntOrNull()

  age?.let {

    println("You are $it years old");

  } ?: println("Wrong input!");

}

 

در این مثال از توابع در کاتلین، ابتدا مقدار سن را از کاربر می‌گیریم. چون مقدار ورودی ممکن است null باشد، از ?. استفاده می‌کنیم تا بررسی کنیم آیا مقداری وارد شده است یا خیر. سپس، با استفاده از let، فقط درصورتی که مقدار سن معتبر باشد (یعنی null نباشد)، آن را چاپ می‌کنیم. درغیراین‌صورت، پیام خطایی نمایش داده می‌شود.

تابع apply: تغییر و تحول آبجکت‌ ها

تابع apply زمانی کاربرد دارد که می‌خواهید ویژگی‌ها (properties) یا رفتار (behaviour) یک آبجکت را تغییر دهید. این تابع به شما اجازه می‌دهد تا به‌صورت زنجیره‌ای، مقادیر جدید را به ویژگی‌های آبجکت اختصاص دهید.

 

fun main() {

  val me = Person().apply {

    name = "Nishant"

    age = 19

    gender = 'M'

  }

  println(me)

}

 

در این مثال، یک آبجکت از کلاس Person ساختیم. سپس، با استفاده از apply ویژگی‌های این آبجکت را مقداردهی کردیم.

تابع with: کار با ویژگی‌ های آبجکت

تابع with شبیه به apply عمل می‌کند، با این تفاوت که خروجی آن خود آبجکت است. این تابع بیشتر جنبه‌ خوانایی کد را تقویت می‌کند.

 

fun main() {

  val me = with(Person()) {

    name = "Nishant"

    age = 19

    gender = 'M'

  }

  println(me)

}

 

همانند مثال قبل، یک آبجکت از کلاس Person ساختیم و با استفاده از with ، ویژگی‌های آن را مقداردهی کردیم. درنهایت، خود آبجکت خروجی تابع with است.

تابع run: شبیه به let اما با دسترسی this

تابع run از ساده‌ترین توابع در کاتلین تا حدودی شبیه let است؛ با این تفاوت که در داخل بلوک run ، به جای it می‌توانید از this برای اشاره به آبجکت استفاده کنید.

 

fun main() {

  val me = Person(

    name = "Nishant",

    age = 19,

    gender = 'M'

  )

  me.run {

    println("My name is $name and I am $age years old.");

  }

}

 

در این مثال، یک آبجکت از کلاس Person ساختیم و سپس با استفاده از run روی این آبجکت، اطلاعات آن را چاپ کردیم. در بلوک run به دلیل اینکه تابع روی خود آبجکت فراخوانی شده است، از this برای اشاره به ویژگی‌های آن می‌توانیم استفاده کنیم.

تابع also: انجام کارهای اضافی روی آبجکت

تابع also ، یکی از کاربردی‌ترین توابع در کاتلین ، یک آبجکت را به‌عنوان ورودی می‌گیرد و به شما اجازه می‌دهد تا کارهای اضافی را روی آن انجام دهید. خروجی این تابع، خود آبجکت است.

 

fun main() {

  Person(

    name = "Nishant",

    age = 19,

    gender = 'M'

  ).also { println(it) }

}

 

در این مثال، یک آبجکت از کلاس Person ساختیم و به‌کمک also آن را چاپ کردیم.

ارجاع توابع در کاتلین: نوشتن کد کوتاه‌ تر و تمیزتر

در مثال قبلی، کد ما برای محاسبه طول کلمات در یک جمله، کمی طولانی بود. در کاتلین راه حل‌هایی برای نوشتن کد کوتاه‌تر و تمیزتر وجود دارد. یکی از این راه‌حل‌ها، استفاده از ارجاع توابع در کاتلین با توابع مرتبه بالاتر (higher-order functions) است.

 

fun main() {

  val input = readLine()

  input?.let {

    val sentence = it.split(" ")

    sentence.map(String::length).also(::println)

  }

}

 

در این کد، ابتدا ورودی کاربر را با ()readLine می‌خوانیم و آن را در متغیر input ذخیره می‌کنیم. سپس، با استفاده از let بررسی می‌کنیم که آیا input مقداری دارد یا خیر. اگر input مقداری داشته باشد، آن را با split به لیستی از کلمات (جداشده با فاصله) تبدیل می‌کنیم و در متغیر sentence ذخیره می‌کنیم. 

حالا می‌خواهیم طول تک‌به‌تک کلمات در جمله را محاسبه کنیم. به‌جای نوشتن یک تابع جداگانه برای این کار، از ارجاع تابع String::length استفاده می‌کنیم. String::length به تابع داخلی length در کلاس String اشاره می‌کند. این تابع، طول یک رشته را برمی‌گرداند.

اکنون با استفاده از متد map روی لیست sentence ، طول تک‌به‌تک کلمات را محاسبه می‌کنیم و نتیجه را در لیست جدید ذخیره می‌کنیم. در انتها، از ارجاع تابع ::println برای چاپ‌کردن لیست نهایی (که حاوی طول کلمات است) استفاده می‌کنیم.

جمع بندی: توابع در کاتلین 

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

چه رتبه ای می‌دهید؟

میانگین ۵ / ۵. از مجموع ۲

اولین نفر باش

گوش به زنگ یلدا
title sign
معرفی نویسنده
تیم فنی نیک آموز
مقالات
401 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
تیم فنی نیک آموز
title sign
دیدگاه کاربران