




أنواع الدوال في لغة الكوتلن
الـ Local Function وتسمى كذلك بالـ Nested Function
من المعروف أن العناصر لها انواع عديدة كالحروف Char والسلاسل النصية String والارقام Int وما الى ذلك. ولاننسى الأنواع التي نقوم بإنشائها نحن بشكل مخصص.
مثال يوضح بعض من الأنواع للعناصر:
كود:
val x: Int = 20 val name: String = “Mohammad” val gotham: City = City(“Gotham”)
- في السطر الاول لدينا كائن عددي نوعه هو Int.
- في السطر الثاني لدينا كائن نصي نوعه هو String.
- في السطر الثالث لدينا كائن مدينة ونوعه هو City قمنا بإنشائه نحن.
كذلك كل دالة في لغة الكوتلن لها نوع معين. فليس فقط العناصر لديها انواع. ولمعرفة كيفية فهم انواع الدوال فنحن نعبر عن الدالة بالقوسين (), وبداخلهما نضع انواع المدخلات لها. ونعبر عن النوع التي تخرجة الدالة بالسهم -> ومن ثم يتبعه نوع المخرج. وهكذا نستطيع ان نستشف نوع الدالة من هذه الاشياء.
الصيغة العامة لنوع الدالة التي لاتأخذ مدخلات ولاتخرج شئ:
() -> Unit
- لاحظ ان القوسين الفارغين نعبر عنهم عن مدخلات الدالة. ولاحظ ان النوع Unit نعبر عنه لتمثيل اللا شئ (جافا: تستطيع فهمة كأنه النوع Void).
بعض الأمثلة لهذا النوع من الدوال:
كود:
[/SIZE][/FONT][/B][/LEFT]
[RIGHT][/RIGHT]
[LEFT] fun message() { println("Message") }
لاحظ ان نوع المخرج لم نكتبه بل يستطيع المترجم Compiler أن يستشفه بنفسه فلا داعي لكتابته هكذا:
كود:
fun message(): Unit { println("Message") }
أما اذا كانت الدالة تأخد عدد من الانواع وتخرج نوع فنستطيع التعبير عنها كالتالي:
(Type, Type) -> Return Type
مثال لدالة من هذا النوع, تأخذ مدخلين من نوع Int وتخرج مجموعهم كنوع Int:
كود:
fun sum(a: Int, b: Int): Int { return a + b }
- لاحظ أن النوع Type هنا هو Int لكل من المدخلين والمخرج.
وفي البرمجة الدالية, الدوال تستطيع اخراج دالة او اخذ دالة كمعطى لها, وتكون الصيغة العامة لها على الشكل التالي:
كود:
()->()->Unit
- وهذا معناة أن دالة لاتأخد مدخلات وتخرج دالة وتلك الدالة لاتأخذ مدخلات ولاترجع شئ.
مثال لدالة من هذا النوع:
كود:
fun foo(boo: () -> Unit): Unit { }
- لاحظ أن الدالة foo تأخد دالة اخرى بأسم boo ولاتخرج شئ.
مثال لدالة تأخد رقمين من نوع Int وتأخد ثالث كدالة لإجراء العملية الحسابية عليهم, ولاتخرج شئ بل تطبع الناتج:
كود:
fun calculator(a: Int, b: Int, operation: (Int, Int) -> Int): Unit { println("The result is " + operation(a, b)) }
- لاحظ أن الدالة calculator تعتبر من صنف الدوال الـ Higher-Order Functions وهذا يعني انها قادرة على اخذ دالة او اخراج دالة اخرى. هنا قامت بأخذ دالة من من نوع (Int, Int) -> Int كمدخل ثالث.
ونستخدمها هكذا:
كود:
calculator(2, 4, ::sum)
- لاحظ أننا قمنا بمناداة الدالة calculator واعطيناها رقمان ٢ و ٤ ثم اعطيناها دالة اخرى قد أنشئناها مسبقاً بأسم sum والتي تمثل عملية الجمع.
- لاحظ اننا قمنا بالاشارة الى الدالة sum بطريقة :: ثم اسم الدالة. وهذا يسمى بالـ Callable Reference ونستخدمه للإشارة الى الدوال من اصناف الـ Top Level و Local و Member و Extension في القسم التالي ستتعرفهم عليهم.
لاتجهد نفسك في معرفة حفظ هذه الاشياء فكثرة الممارسة وقرائة شفرة الدوال ستجد انك تفهم انواعهم.
أصناف الدوال الدالية في لغة الكوتلنفي هذا القسم سوف نتعرف على أصناف الدوال التي تقدمهم لغة الكوتلن كخطوات نحو البرمجة الدالية Functional Programming والتي تساعدنا في إنشاء نظام تصريحي من خلال البرمجة Declarative Programming يعتمد على التصريح بطلب ماذا نريد من النظام أن يفعل What.
الـ Lambdaهذه هي اهم دالة من خلالها نستطيع اختصار وفعل اشياء كثيرة بها. تنطق لامبدا lambda تعتبر نوع مختصر من انواع الدوال وتأتي بدون اسم. أي اننا لانحتاج الى كتابة اسم لها فقط الـ {}. وتتميز بإختصار الكتابه. فهي عبارة عن قوسين {} بداخلهما نكتب مانريد منها ان تفعله. وتعتبر مناسبة للإشياء الصغيرة.
{ 4 * 4 }
الـ Anonymous Functionالدالة المجهولة وهي دالة تأتي بدون اسم كالـ لامبدا. مايميز هذه انها تستطيع تحديد نوع الارجاع return. وكذلك الراحة في كتابة الكثير من الاسطر البرمجية بداخلها. اي اكثر وضوح Explicit من اللامبدا. مناسبة للإشياء اللتي تحتاج بعض الاسطر البرمجية وتحديد للمخرج.
كود:
// Anonymous Function fun(x: Int, y: Int): Int { return x + y }
اذن نستخدم لامبدا اذا لم نرد تحديد نوع الارجاع return. اما اذا فنستخدم الداله المجهوله anonymous. وهنا يكمل فرق بينهما.
الـ Literal Functionبالمختصر الدوال الحرفية (الـ Literal Function) هي Lambda Function او Anonymous Function تم اسنادها الى اسم متغير (Function Reference).
كود:
[/LEFT]
[RIGHT]
[/RIGHT]
[LEFT] // Lambda Function as Literal Function // Type of ‘()’ take no args. // ‘Int’ is return type. val lambdaFunctionLiteral: () -> Int = { 4 * 4 } // Anonymous Function as Literal Function // Type of ‘(Int, Int)’ take two args type ‘Int’ // ‘-> Int’ means return type is int. val anonymousFunctionLiteral: (Int, Int) -> Int = fun(x: Int, y: Int): Int { return x + y }
- لاحظ طريقة اسناد دالة من نوع لامبدا الى المتغير lambdaFunctionLiteral لتصبح دالة حرفية literal.
- لاحظ طريقة اسناد دالة من نوع مجهول الى المتغير anonymousFunctionLiteral لتصبح دالة حرفية literal.
اذن عندما نسند الدوال السابقه (اللامبدا و المجهوله) الى متغير ما, نستطيع تسميتها بالـ Literal Function.
الـ Higher Order Functionعبارة عن دالة تستطيع اخد دالة اخرى كمدخل لها Parameter. او اخراج دالة اخرى كمخرج.
كود:
// Lambdas as Literal Function // Function type is (Int, Int) -> Int val sumOperation: (Int, Int) -> Int = { x: Int, y: Int -> x + y } val mulOperation: (Int, Int) -> Int = { x: Int, y: Int -> x * y } // Higher Order Function // Parameters: // 1. ‘X’ and ‘y’ Type is Int. // 2. ‘Function’ Type is (Int, Int) -> Int. fun runOperation(x: Int, y: Int, operation: (Int, Int) -> Int): Int { return operation(x, y) } // Usage runOperation(8, 2, mulOperation) // 16 runOperation(8, 2, sumOperation) // 10
- دالتان حرفيتان Lambdas Literal بإسم sumOperation و mulOperation لعملية الجمع والقسمة.
- دالة عالية المستوى Higher Order بإسم runOperation تأخد متغيرين Int ودالة اخرى, وتخرج Int.
- لاحظ طريقة الاستخدام وذلك بتمرير لها رقمين ودالة ما.
مثال آخر لدالة الـ Higher Order Function تأخذ دوال كمدخلات:
كود:
[/SIZE][/FONT][/LEFT]
[LEFT] // Higher Order Function // 'x' & 'y' Type is Int. // 'function' Type is (Int, Int) -> Int fun runOperation(x: Int, y: Int, operation:(Int, Int) -> Int): Int { return operation(x, y) }[/LEFT]
- المدخلات للمتغيران x و y من نوع Int.
- المدخل للدالة التي بإسم operation من نوع (Int,Int) -> Int.
الاستخدام من خلال اعطائها المعطيات المطلوبة (ارقام وداله ما):
كود:
fun main() { // Usage with lambda runOperation(8, 2) { x: Int, y: Int -> x / y } // 4 // Usage with Anonymous Function runOperation(5, 1, fun(x: Int, y: Int): Int { return x - y } ) // 4 }
- لاحظ تأخد دالة من نوع Lambda بشكل مختصر.
- واستخدام آخر تأخد دالة من نوع Anonymous Function.
مثال لدالة الـ Higher Order Function تقوم بإرجاع دالة ما.
كود:
// Normal Functions fun mulOperation(x: Int, y: Int): Int { return x * y } fun sumOperation(x: Int, y: Int): Int { return x + y } // Higher Order Function fun getOperationMulOrSum(operation: String): ((x: Int, y: Int) -> Int) { return if (operation == "mul" { ::mulOperation } else { ::sumOperation } }
- دالتين عادية بإسم mulOperation و sumOperation لعمليتا الضرب والجمع.
- دالة عالية المستوى بإسم getOperationMulOrSum تأخد نص عبارة عن أسم للعملية, وتقوم بإخراج دالة من خلال ندائها من مكان ما بإستخدام ::.
- لاحظ استخدام الرمز :: وذلك للإشارة الى الدالة, يسمى بالـ Callable References او Feature Literals هنا تم استخدامة كـ callable للإشارة الى دالة موجودة مسبقاً.
الاستخدام:
كود:
fun main() { val mulResult: Int = getOperationMulOrSum("mul")(50, 3) // 150 val sumResult: Int = getOperationMulOrSum("sum")(50, 3) // 53 }
مثال آخر لدالة الـ Higher Order Function تقوم بإرجاع دالة ما. تاره من نوع Anonymous Function وتارى اخرى من نوع Lambda بشكل مختصر. ولكن يجب ان تكون من نفس النوع المحدد الا وهو (Int, Int -> Int):
كود:
// Higher Order Function fun calculator(operation: String): ((x: Int, y: Int) -> Int) { when (operator) { "sum" -> return fun(x: Int, y: Int): Int { return x + y } "sub" -> return fun(x: Int, y: Int): Int { return x - y } "mul" -> return fun { x: Int, y: Int -> x * y } "div" -> return fun { x: Int, y: Int -> x / y } } return fun(_: Int, _: Int): Int { return 0} }
- لاحظ الرمز _ يعبر عن تسمية للمتغير الذي لن يستخدم في الدالة.
الاستخدام:
كود:
fun main() { calculator("sum")(4, 6) // 10 calculator("div")(12, 3) // 4 }
الـ Top Level Functionهي الدوال التي لاتنتمي الى اي فئه class او واجهة interface او عنصر object. بل يتم كتابتها في اي ملف كوتلن. تستطيع تشبيهها بالـ Static Methods في الجافا, تناديها من اي مكان في تطبيقك. ولكن لاتنسى ان تعمل لها import.
كود:
In a kotlin file.kt fun log(message: String) { println(message) } // Usage in other classes or files fun main() { log(“Hi from level function”) }
الـ Member Functionsكل دالة نكتبها بداخل فئة class او عنصر Object نستطيع تسميتها بالـ Member Functions. نستطيع نداء هذا النوع من العناصر Object المنشئه من هذه الفئة (لاشئ جديد هنا).
كود:
// Class City class City { val population = 10014 // Member Function fun printPopulation() { println(population) } } // Usage val city = City() city.printPopulation() [/LEFT]
[RIGHT] [/RIGHT]
[LEFT]
عبارة عن دالة بداخل دالة. كما بالمثال:
// Local Function | Nested Function // Normal Function fun mul(x: Int, y: Int): Int { // Validation require(x != 0) { "x must not be zero" } require(y != 0) { "y must not be zero" } // Local Function fun calculate(x: Int, y: Int): Int { return x + y } // Usage of Local Function return calculate(x, y) }
- دالة عملية الضرب, تتأكد ان المدخل ليس بصفر (ربما تقذف Exception تذكر ان هذا العمل ضد طريقة الـ Functional Programming).
- ثم توجد دالتنا الـ Local بداخلها للقيام بعملية الضرب بحذ ذاتها.
الـ Extension Functionدالة تم الحاقها بفئة class بحيث تكتسبها تلك الفئة كدالة لها. وظيفتها اضافة تصرف الى فئه دون التعديل على شفرتها.
مثال لدالة إضافية تقوم بالتحقق من ازدواجية الرقم, تم الحاقها بفئة الـ Int. وآخر لدالة تطبع قيم اي متسلسلة تم الحاقها بالـ Collection.
// Extension Function fun Int.isEven() { println(this % 2 == 0) } // Usage 4.isEven()
وتأتي مع الدوال (كالـ Extension Function) كلمات Keyword في لغة الكوتلن نستطيع استخدامها اثناء تعريفها مثل:
- الـ infix: لجعلها تنادى بدون استخدام النقطة.
- و inline: لجعل الدالة خفيفة على المترجم compiler.
- و reified: للدلاله على الفئة class بدون تحديدها.
وبالرغم من كل ماتقدمة لغة الكوتلن من دوال وإشياء تصب في مصلحة البرمجة الدالية. ولكن يستحيل تحقيقها بشكل كلي. فقط تذكر ان هذه الاشياء وجدت لتسهيل برمجتك ولست مجبراً عليها. في النهاية كوتلن لغة:
- دالية Functional.
- وكائنية OOP.
- وتستطيع الخلط او استخدام احدها فقط