دوال tailrec
حسّنوا الاستدعاء الذاتي
دوال tailrec درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ما الاستدعاء الذاتي النهائي؟
تكون الدالة ذات استدعاء ذاتي نهائي عندما يكون استدعاؤها الذاتي آخر عملية فيها. عندها يمكن لـ Kotlin تحسينها وتحويلها إلى حلقة، مما يتجنب تجاوز المكدس.
tailrec fun countdown(n: Int) {
if (n < 0) return
println(n)
countdown(n - 1)
}
fun main() {
countdown(3)
}معدِّل tailrec
أضيفوا المعدِّل tailrec، وسيعيد المترجم كتابة الاستدعاء الذاتي على هيئة تكرار باستخدام مساحة مكدس ثابتة.
tailrec fun sum(n: Int, acc: Int = 0): Int {
if (n == 0) return acc
return sum(n - 1, acc + n)
}
fun main() {
println(sum(100))
}نمط المُجمِّع
لجعل الاستدعاء الذاتي نهائيًا، انقلوا النتائج في معامل مُجمِّع حتى لا يبقى شيء لحسابه بعد الاستدعاء.
tailrec fun factorial(n: Int, acc: Long = 1): Long {
if (n <= 1) return acc
return factorial(n - 1, acc * n)
}
fun main() {
println(factorial(10))
}لماذا يجب أن يكون الاستدعاء أخيرًا؟
إذا حدث أي شيء بعد الاستدعاء الذاتي، مثل ضرب نتيجته، فلن يكون الاستدعاء في الموضع النهائي، وبالتالي لا يمكن تحسينه.
tailrec fun length(s: String, acc: Int = 0): Int {
if (s.isEmpty()) return acc
return length(s.drop(1), acc + 1)
}
fun main() {
println(length("hello"))
}مثال مضاد للاستدعاء الذاتي غير النهائي
هذه الدالة لحساب المضروب ليست ذات استدعاء ذاتي نهائي، لأن عملية الضرب تحدث بعد عودة الاستدعاء. وسيؤدي تعليمها بـ tailrec إلى إصدار تحذير.
fun badFactorial(n: Int): Long {
if (n <= 1) return 1
return n * badFactorial(n - 1)
}
fun main() {
println(badFactorial(5))
}تجنب تجاوز المكدس
قد يؤدي الاستدعاء الذاتي العميق من دون tailrec إلى تعطل البرنامج. أما معه، فتعمل حتى المدخلات الكبيرة باستخدام مساحة مكدس ثابتة.
tailrec fun count(n: Int, acc: Int = 0): Int {
if (n == 0) return acc
return count(n - 1, acc + 1)
}
fun main() {
println(count(100000))
}تحقق المترجم
إذا علّمتم دالة بـ tailrec لكن الاستدعاء ليس في الموضع النهائي، فسيصدر المترجم تحذيرًا ولن يحسّنها. ثقوا بالتحذير.
tailrec fun gcd(a: Int, b: Int): Int {
if (b == 0) return a
return gcd(b, a % b)
}
fun main() {
println(gcd(48, 18))
}الاستدعاء الذاتي النهائي مقابل الحلقة
تُترجم دالة tailrec تقريبًا إلى الشيفرة نفسها التي تُترجم إليها الحلقة المكافئة، لكنها تعبّر عن الخوارزمية بصيغة الاستدعاء الذاتي.
tailrec fun powerOfTwo(n: Int, acc: Long = 1): Long {
if (n == 0) return acc
return powerOfTwo(n - 1, acc * 2)
}
fun main() {
println(powerOfTwo(10))
}معاملات متعددة
غالبًا ما تمرر الدوال ذات الاستدعاء الذاتي النهائي عدة معاملات للحالة، ويُحدَّث جميعها في الاستدعاء الذاتي.
tailrec fun fib(n: Int, a: Long = 0, b: Long = 1): Long {
if (n == 0) return a
return fib(n - 1, b, a + b)
}
fun main() {
println(fib(20))
}العكس باستخدام tailrec
يمكن لمُجمِّع أن يبني نتيجة مثل سلسلة نصية معكوسة.
tailrec fun reverse(s: String, acc: String = ""): String {
if (s.isEmpty()) return acc
return reverse(s.drop(1), s.first() + acc)
}
fun main() {
println(reverse("kotlin"))
}بحث عملي
يمكن تحويل عمليات البحث التكرارية بسهولة إلى استدعاء ذاتي نهائي.
tailrec fun indexOf(list: List<Int>, target: Int, i: Int = 0): Int {
if (i >= list.size) return -1
if (list[i] == target) return i
return indexOf(list, target, i + 1)
}
fun main() {
println(indexOf(listOf(5, 6, 7), 7))
}تحقق سريع
اختبروا مدى فهمكم لدوال tailrec.
مراجعة
لقد تعلمتم دوال tailrec:
- يحوّل
tailrecالاستدعاء الذاتي في الموضع النهائي إلى حلقة، مما يتجنب تجاوز المكدس. - يجب أن يكون الاستدعاء الذاتي آخر عملية.
- استخدموا معاملًا مُجمِّعًا للوصول إلى الصيغة النهائية.
- يصدر المترجم تحذيرًا عندما يتعذر تحسين الدالة.
tailrec fun sum(n: Int, acc: Int = 0): Int =
if (n == 0) acc else sum(n - 1, acc + n)
fun main() {
println(sum(50))
}الأسئلة الشائعة
هل درس «دوال tailrec» مجاني؟
نعم — نص درس «دوال tailrec» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «دوال tailrec»؟
حسّنوا الاستدعاء الذاتي تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «دوال tailrec»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.