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

عبارت لامبدا

توضیحات

عبارات لامبدا و توابع بی نام در کاتلین دو موضوع از برنامه نویسی تابعی هستند. این دو کاربرد های متعددی دارن و در فریمورک های مختلف از جمله اندروید استفاده های زیادی دارن.

به عبارت لامبدا و تابع بی نام، توابع تحت لفظی (Function Literals) گفته میشه.

توابع تحت لفظی رو مثل توابع معمولی تعریف نمیکنیم بلکه مانند یک متغیر تعریفشون میکنیم و هنگام صدا زدن مانند تابع معمولی صداشون میزنیم.

عبارات لامبدا و توابع بی نام هر دو از یک جنس هستند و تنها در مدل پیاده سازی باهم فرق دارن. مثلا اگه بخوایم برای عبارت لامبدا یک متغیر تعریف کنیم میتونیم بجای عبارت لامبدا تابع بی نامو بهش اختصاص بدیم و برعکس.

یکی از تفاوت هایی که تابع بی نام با عبارت لامبدا داره در استفاده از return است، در تابع بی نام به صورت آشکار میشه از return استفاده کرد در حالی که در عبارت لامبدا به صورت آشکار نمیشه استفاده کرد مگه با تعریف برچسب برای عبارت.

در ادامه به بررسی این دو تابع میپردازیم.

بررسی یه ویژگی از کاتلین

در کاتلین همه چیز دارای مقدار است؛ تقریبا هر متغیر و تابعی که وجود داره، حتی void که مفدارش Unit است.

فرض کنید تو جاوا تابعی رو صدا میزنیم اگه مقداریو برگردونه میتونیم به متغیر اختصاص بدیم:

private String myMethod(){ return "This is a result type of String" } //correct String result = myMethod();

اگه مقداریو بر نگردونه چیزی رو نمیتونیم به متغیر اختصاص بدیم و دچار خطای کامپایل میشیم:

private void myMethod(){ ... } //compile error String result = myMethod()

در کاتلین void هم یک مقدار داره از نوع Unit :

private fun myMethod(){ ... } //correct val result = myMethod()

دونستن این موضوع شاید به درک بهتر عبارت لامبدا (Lambda Expression) و توابع بی نام (Anonymous Function) کمک کنه.

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

برای تعریف متغیر هایی از جنس لامبدا مانند متغیر های معمولی عمل میکنیم:

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

اسم متغیر: اسم دلخواهیه که برای متغیر در نظر میگیریم.

نوع متغیر: همان نوع لانداییه که میخوایم تعریف کنیم در داخل () پارامتر هایی که میخوایم عبارت داشته باشه رو تعریف میکنیم و Type همان نوعیست که عبارت بر میگردونه.

مقدار لامبدا: همان مقدار متغیر است و با {...} متغیرو مقداردهی میکنیم.

اگه بخوایم عبارت پارامتر داشته باشه به صورت زیر براش پارامتر تعریف میکنیم:

val myLambda: (T0, T1 , ... , Tn) -> Type = { t0, t1, ... tn -> ... type }

در بالا T0, T1, ..., Tn پارامتر هاییست که میخوایم عبارت داشته باشه.

t0, t1, ..., tn اسامی دلخواهیه که به پارامتر ها اختصاص میدیم و داخل {} از پارامتر ها استفاده میکنیم.

type متغیری از جنس Type است که برگردونده میشه.

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

val t0 = T0() val t1 = T1() ... val tn = Tn() val type = myLambda(t0, t1, ..., tn)

مثال:

val myLambda: () -> String = { "Hello From Lambda" }

در مثال بالا عبارت لاندا بدون پارامتر است و مقدار "Hello From Lambda" رو پس از اجرا برمیگردونه.

صدا زدن عبارت به صورت تابع:

val result: String = myLambda()

مثال:

val myLambda: (String) -> String = { it -> "Hello $it, From Lambda!" }

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

صدا زدن عبارت به صورت تابع:

val name = "Joe" val result: String = myLambda(name) println(result)

مثال:

val myLambda: (String , Int) -> String = { name , age -> "My name is $name, I'm $age years old, this is a message from lambda expmression" }

در مثال بالا عبارت لاندا دارای دو پارامتر است یکی برای اسم و دیگری برای سن.

توجه:

name و age اسم های دلخواه برای پارامتر های تعریف شده هستند

صدا زدن عبارت به صورت تابع:

val name = "Joe" val age = 24 val result: String = myLambda(name, age) println(result)

برچسب زدن به عبارت لامبدا:

استفاده از کلیدواژه ی return داخل لامبدا ممنوعه مگه در مواردی که لامبدا خطی (inline) باشه یا برای مقدار لامبدا برچسب تعریف کرده باشیم.

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

val myLambda: () -> String = mylambda@{ return@mylambda "Hello From Lambda" }

در بالا برچسب ‎myLambda@{...} رو برای عبارت تعریف کردیم. و از return با برچسبی که تعریف کردیم میتونیم استفاده کنیم.

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

همینطور که از اسمش مشخصه این توابع اسم ندارن. نحوه ی بیان کردنشون مانند توابع معمولیه. فرقشون با توابع معمولی تو نداشتن اسمه. این توابع رو میتونیم به یک متغیر اختصاص بدیم و برای صدا زدنشون مانند تابع معمولی عمل میکنیم.

به این توابع ، تابع anonymous ننیز گفته میشه.

مثال:

تعریف تابع:

val myAnonymous: () -> Unit = fun(){ println("Hello From Anonymous") }

صدا زدن تابع:

myAnonymous()

مثال:

تعریف تابع:

val myAnonymous: (String) -> String = fun(name: String): String{ return "Hello $name from Anonymous" }

صدا زدن تابع:

val name = "Joe" val message = myAnonymous(name) println(message)

مثال:

تعریف تابع:

val myAnonymous: (String, Int) -> String = fun(name: String, age: Int): String { return "Hello my name is $name, I'm $age years old this is a message from anonymous" }

صدا زدن تابع:

val name = "Joe" val age = 24 val message = myAnonymous(name , age) println(message)

توابع تحت لفظی با receiver

میتونیم عبارت لامبدا رو با یک کلاس receiver بنویسیم. سپس به اعضای کلاس در داخل تابع دسترسی داریم. این کار شبیه تعریف اکستنشن ها در کاتلین است.

مثال:

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

val containsDigit: String.(Int) -> Boolean = { digit -> val d = digit.toString() var containsDigit = false if(d.length == 1){ for(ch in this){ if(ch.toString() == d){ containsDigit = true break } } } containsDigit } //صدا زدن تابع fun main(){ var s = "A binary number 01001 equals 9 in decimal" println("s contains 9? ${s.containsDigit(9)}") println("s contains 5? ${s.containsDigit(5)}") println("s contains 0? ${s.containsDigit(0)}") println("s contains 1? ${s.containsDigit(1)}") }

مثال:

در مثال زیر یک عبارت بدون پارامتر تعریف میکنیم که بررسی میکنه طول یک String زوج است یا خیر.

val isLengthEven: String.() -> Boolean { (length % 2) == 0 } fun main(){ val s = "Lambda Expression" val even = s.isLengthEven() println("Is $s length even? $even") }

تابع بی نام هم مانند عبارت لامبدا میتونه کلاس receiver داشته باشه.

مثال:

val divide = fun Int.(other: Int): Int{ return this / other } fun main(){ val a = 8 val b = 2 val result = a.divide(b) println("$a divided by $b equals $result")

خلاصه

- دو عبارت بی نام و تابع لامبدا جزو توابع تحت لفظی هستند

- توابع تحت لفظی رو مانند یک متغیر تعریف میکنیم و مثل تابع معمولی صدا میزنیم

میتونیم مثل اکستنشن ها توابع تحت لفظی رو با رسیور تعریف کنیم

یکی از ویژگی هایی که کاتلینو با جاوا متمایز کرده قدرت functionality کاتلینه. در این مقاله با توابع anonymous و عبارت لاندا در کاتلین اشنا شدیم.

امیدوارم براتون مفید واقع شده باشه.🌸🌸🌸

arrow_drop_up
کپی شد!