الفرق بين المراجعتين لصفحة: «Kotlin/returns»
طلا ملخص تعديل |
تعديل مصطلح خاطئ |
||
سطر 32: | سطر 32: | ||
println("this point is unreachable") | println("this point is unreachable") | ||
} | } | ||
</syntaxhighlight>سيعود تعبير الرجوع <code>return</code> من أقرب دالة محيطة (enclosing) وهي في المثال هنا <code>foo()</code>، ويُلاحظ أنّ عمليات الرجوع غير المحليّة (non-local) هذه مدعومةٌ فقط في تعابير lambda المُمرَّرة إلى الدوال | </syntaxhighlight>سيعود تعبير الرجوع <code>return</code> من أقرب دالة محيطة (enclosing) وهي في المثال هنا <code>foo()</code>، ويُلاحظ أنّ عمليات الرجوع غير المحليّة (non-local) هذه مدعومةٌ فقط في تعابير lambda المُمرَّرة إلى الدوال المباشرة (inline functions)، أما إن كان الرجوع من تعبير lambda فتجب حينئذٍ تسميته لتقييد <code>return</code> به، مثل:<syntaxhighlight lang="kotlin"> | ||
fun foo() { | fun foo() { | ||
listOf(1, 2, 3, 4, 5).forEach lit@{ | listOf(1, 2, 3, 4, 5).forEach lit@{ |
مراجعة 10:59، 29 مارس 2018
تعابير القفز
تمتاز لغة Kotlin بوجود ثلاثة تعابير (expressions) لنقل سياق البرنامج وهي:
return
: للرجوع من أقرب دالةٍ محيطةٍ (enclosing) أو دالةٍ مجهولةٍ (anonymous function).break
: تنهي أقرب حلقةٍ محيطة.continue
: تستمر بالخطوة التالية لأقرب حلقةٍ محيطة.
إذ يُسمَح باستخدام أيّ من التعابير السابقة كجزءٍ من تعبيرٍ أكبر، مثل:
val s = person.name ?: return
ونوع هذه التعابير هو Nothing type.
تسمية الأوامر Break و Continue
يٌتاح في لغة Kotlin تحديد تسميةٍ (label) لأيّ تعبير، إذ تتألف هذه التسمية من مُحدِّدٍ (identifier) يُتبَع بالرمز @
مثل: abc@
أو fooBar@
وتُوضع قبل التعبير مباشرةً، مثل:
loop@ for (i in 1..100) {
// ...
}
وبعد تسمية الحلقة نستطيع تقييدَ الأمر break
أو continue
بالتسمية كما في الشيفرة الآتية:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
حيث ستنتهي الحلقة عند تحقُّق الشرط if
والوصول إلى break
التي بدورها ستنقل سياق البرنامج إلى نقطة التنفيذ التي تلي -مباشرةً- الحلقة ذات التسمية المذكورة (وهي loop)، أما continue
فستنقل سياق البرنامج إلى التكرار التالي لتلك الحلقة.
العودة إلى نقطة مسماة (Label)
من المحتمل أن تتداخل الدوال بوجود قيم الدوال (literals) أو الدوال المحليّة (local) أو تعابير الكائن (object expressions)، وبالتالي فإن الكلمة المفتاحيّة return
ستعود بسياق البرنامج من الدالة الخارجيّة وأكثر الحالات أهميةً هي العودة من تعبير lambda، ففي الشيفرة الآتية مثلًا:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // العودة غير المحلية إلى حيث استدعيت الدالة foo()
print(it)
}
println("this point is unreachable")
}
سيعود تعبير الرجوع return
من أقرب دالة محيطة (enclosing) وهي في المثال هنا foo()
، ويُلاحظ أنّ عمليات الرجوع غير المحليّة (non-local) هذه مدعومةٌ فقط في تعابير lambda المُمرَّرة إلى الدوال المباشرة (inline functions)، أما إن كان الرجوع من تعبير lambda فتجب حينئذٍ تسميته لتقييد return
به، مثل:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // رجوع محلي إلى حيث استدعاء lambda
// والذي هو فعليًا حلقة forEach
print(it)
}
print(" done with explicit label")
}
إذ يتمّ الرجوع الآن فقط من تعبير lambda، ولكن من الأسهل في معظم الأحيان استخدامُ التسمية الضمنيّة (implicit) وهي تسميةٌ لها اسم الدالة نفسها التي يُمرَّر لها تعبير lambda أيّ:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // رجوع محلي إلى حيث استدعاء lambda
// والذي هو فعليًا حلقة forEach
print(it)
}
print(" done with implicit label")
}
وقد يُستبدَل تعبير lambda لتحل محله دالةٌ مجهولةٌ (anonymous function) إذ يكون أمر الرجوع return
فيها إلى الدالة ذاتها، مثل:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // رجوع محلي إلى نفس المستدعي لتعبير lambda
// أي حلقة forEach
print(it)
}
print(" done with explicit label")
}
ويُلاحظ أن استخدام الرجوع المحليّ في الأمثلة الثلاثة السابقة مشابهٌ لاستخدام continue
في الحلقات العاديّة، ولكن لا يوجد ما يكافئ الأمر break
، وأفضل طريقةٍ لمماثلته هي إضافة lambda أخرى متداخلة (nesting) والعودة غير المحليّة منها ، مثل:
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // رجوع غير محلي من التعبير المُمَرَّر
print(it)
}
}
print(" done with nested loop")
}
وعند إعادة قيمةٍ ما فإن الأفضليّة تكون للرجوع المقيَّد أي أنّ الشيفرة:
return@a 1
تعني "إعادة القيمة 1
عند التسمية @a
" وليس "إعادة تعبيرٍ مُسمّىً باسم @a 1
".