Kotlin: شرح تدفق التحكم في كوتلن
آخر تحديث: 2026-08-26
تدفق التحكم في كوتلن ليس مجرد تحكم في التدفق — if وwhen هما تعبيران بقيم إرجاع، مما يجعل منطق توجيه طلبات تشارلي آمنًا وموجزًا.
1. ما ستتعلمه
ifتعبير:val max = if (a > b) a else bwhenبجميع أشكالها: متعددة القيم، شروط الحارس، ربط المتغيراتfor+ المكرر: تكرار على المجموعات، النطاقات، الخرائط- التصنيفات والإرجاعات:
break@label/continue@label/return@forEach - تشارلي عمليًا:
when(order.status)توجيه الطلبات
2. قصة مهندس معمارية حقيقية
(1) مشكلة: جحيم if-else المتداخل
OrderProcessor الخاص بتشارلي في جافا استخدم 5 مستويات من if-else متداخلة لتوجيه الطلبات حسب الحالة — 120 سطر فقط لتحديد أي خط أنابيب يجب استخدامه. عندما انضم بوب الجديد للفريق، أخطأ في شروط الفروع 3 مرات، مما تسبب في حوادث إنتاجية.
(2) حل تعبير when في كوتلن
KOTLIN
// نظيف، شامل، مُتحقَق من المُترجِم
fun route(order: Order): Pipeline = when (order.status) {
Status.PENDING -> PendingPipeline
Status.CONFIRMED -> if (order.total > 10_000) VipPipeline else StandardPipeline
Status.SHIPPED -> TrackingPipeline
Status.CANCELLED -> RefundPipeline
}
فحص شمول تعبير
when+ حارس المُترجِم: فرع مفقود هو خطأ ترجمة. بوب لن يستطيع إدخال مثل هذه الأخطاء مرة أخرى.
3. تعبير if
(1) if تعبير بقيمة إرجاع
KOTLIN
// if كتعبير
val max = if (a > b) a else b
// تعبير if متعدد الفروع
val category = if (total > 10_000) {
println("High value order")
"VIP"
} else if (total > 1_000) {
"PRIORITY"
} else {
"STANDARD"
}
(2) تعبير if مقابل if في جافا
| البعد | Java if | Kotlin if |
|---|---|---|
| الطبيعة | عبارة | تعبير |
| قيمة الإرجاع | لا توجد | قيمة آخر تعبير |
| التعيين | يحتاج متغير إضافي | val x = if(...)... |
| العامل الثلاثي | ?: |
if/else |
KOTLIN
// لا حاجة لعامل ثلاثي - if/else هو العامل الثلاثي
val discount = if (total > 5_000) 0.15 else if (total > 1_000) 0.10 else 0.0
4. when بجميع أشكالها
(1) تعبير when الأساسي
KOTLIN
// مطابقة تامة
val label = when (status) {
"PENDING" -> "Waiting"
"CONFIRMED" -> "Confirmed"
else -> "Unknown"
}
// قيم متعددة في فرع واحد
val isTerminal = when (status) {
"SHIPPED", "DELIVERED", "CANCELLED" -> true
else -> false
}
(2) شروط الحارس (when مع حارس)
KOTLIN
// فروع شرطية مع 'in' والنطاقات
val pipeline = when {
status == "CANCELLED" -> "REFUND"
total > 10_000 && priority == "URGENT" -> "VIP_EXPRESS"
total > 10_000 -> "VIP"
total > 1_000 -> "PRIORITY"
status in listOf("NEW", "PENDING") -> "QUEUE"
else -> "STANDARD"
}
(3) ربط المتغيرات والتفكيك
KOTLIN
// التقاط مع موضوع when
val result = when (val response = httpClient.call()) {
is Success -> "OK: ${response.data}"
is Error -> "Failed: ${response.code}"
}
// response محوّل ذكيًا ومتاح في الفروع
(4) مخطط توجيه حالة الطلب
flowchart TD
A[when order.status] --> B{PENDING}
A --> C{CONFIRMED}
A --> D{SHIPPED}
A --> E{CANCELLED}
B --> B1[Waiting Queue]
C --> C1{total > 10000?}
C1 -->|Yes| C2[VIP Pipeline]
C1 -->|No| C3[Standard Pipeline]
D --> D1[Tracking Pipeline]
E --> E1[Refund Queue]
(5) مقارنة أشكال when
| الشكل | البنية | حالة الاستخدام |
|---|---|---|
| مطابقة تامة | when(status) |
التعدادات / السلاسل / الثوابت |
| مطابقة متعددة القيم | "A", "B" -> ... |
قيم متعددة، نفس الفرع |
| مطابقة النطاق | in 1..10 |
فترات رقمية |
| مطابقة النوع | is String |
توجيه حسب النوع |
| شروط الحارس | when { ... } |
مجموعات شروط معقدة |
| ربط المتغيرات | when(val x = ...) |
التقاط القيم المحسوبة |
5. حلقة for والمكررات
(1) حلقة for الأساسية
KOTLIN
// تكرار النطاق
for (i in 1..10) { /* i من 1 إلى 10 */ }
// تكرار القائمة
for (order in orders) { println(order.id) }
// مع فهرس
for ((index, order) in orders.withIndex()) {
println("[$index] ${order.id}")
}
// تكرار الخريطة
for ((id, status) in orderStatusMap) {
println("$id: $status")
}
(2) بروتوكول المكرر
KOTLIN
// أي فئة بها operator fun iterator() يمكن استخدامها في حلقة for
class OrderBatch(val orders: List<Order>) {
operator fun iterator(): Iterator<Order> = orders.iterator()
}
val batch = OrderBatch(orders)
for (order in batch) { /* يعمل! */ }
(3) مقارنة أنماط حلقة for
| النمط | البنية | حالة الاستخدام |
|---|---|---|
| النطاق | for (i in 1..10) |
حلقات العد |
| المجموعة | for (o in orders) |
تكرار العناصر |
| مع فهرس | for ((i, o) in ...) |
الحاجة للفهرس |
| الخريطة | for ((k,v) in map) |
تكرار المفتاح-القيمة |
| مكرر مخصص | operator fun iterator() |
حاويات مخصصة |
6. حلقة while
KOTLIN
// while قياسية
var retryCount = 0
while (retryCount < 3) {
val success = tryProcessOrder()
if (success) break
retryCount++
}
// do-while (تنفذ مرة واحدة على الأقل)
var input: String
do {
input = readOrderStatus()
} while (input !in listOf("CONFIRM", "CANCEL"))
7. التصنيفات والإرجاعات
(1) تصنيفات الحلقات
KOTLIN
// تصنيف الحلقة الخارجية
loop@ for (batch in batches) {
for (order in batch) {
if (order.status == "CANCELLED") continue@loop // تخطي للدُفعة التالية
if (order.total > 100_000) break@loop // إيقاف جميع المعالجة
process(order)
}
}
(2) إرجاعات lambda
KOTLIN
// إرجاع من lambda (إرجاع محلي)
orders.forEach { order ->
if (order.status == "SKIP") return@forEach // تخطي هذا العنصر فقط
process(order)
}
// إرجاع من الدالة المُغلِقة (إرجاع غير محلي)
// يعمل فقط في الدوال المضمنة
orders.forEach { order ->
if (order.status == "FATAL") return // يخرج من main()
process(order)
}
(3) مقارنة أنواع التصنيفات
| نوع التصنيف | البنية | التأثير |
|---|---|---|
| تصنيف الحلقة | loop@ + break@loop |
الخروج من حلقة محددة |
| تصنيف continue | continue@loop |
القفز لل تكرار التالي من حلقة محددة |
| إرجاع محلي لـ lambda | return@forEach |
الخروج من lambda الحالي فقط |
| إرجاع غير محلي | return |
الخروج من الدالة المُغلِقة (مضمنة فقط) |
8. مثال كامل: آلة حالة طلبات OrderProcessor
KOTLIN
// ============================================
// OrderProcessor - توجيه حسب الحالة
// الميزة: توجيه كامل لحالة الطلب مع when
// ============================================
enum class Status { PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED }
data class Order(val id: String, val total: Double, val status: Status, val region: String)
fun routeOrder(order: Order): String = when (order.status) {
Status.PENDING -> when {
order.region == "EU" -> "EU_COMPLIANCE_QUEUE"
order.total > 10_000 -> "HIGH_VALUE_QUEUE"
else -> "STANDARD_QUEUE"
}
Status.CONFIRMED -> when {
order.total > 5_000 -> "EXPRESS_SHIPPING"
else -> "REGULAR_SHIPPING"
}
Status.SHIPPED -> "TRACKING_UPDATE"
Status.DELIVERED -> "COMPLETION_QUEUE"
Status.CANCELLED -> when {
order.total > 1_000 -> "PRIORITY_REFUND"
else -> "STANDARD_REFUND"
}
}
fun processBatch(orders: List<Order>) {
loop@ for (order in orders) {
when (order.status) {
Status.CANCELLED -> {
println("SKIP: ${order.id} cancelled")
continue@loop
}
else -> {
val pipeline = routeOrder(order)
val priority = if (order.total > 10_000) "CRITICAL" else "NORMAL"
println("PROCESS: ${order.id} -> $pipeline [$priority]")
}
}
}
}
fun main() {
val orders = listOf(
Order("ORD-001", 299.99, Status.CONFIRMED, "US"),
Order("ORD-002", 15_000.00, Status.PENDING, "EU"),
Order("ORD-003", 2_500.00, Status.CONFIRMED, "US"),
Order("ORD-004", 45.50, Status.CANCELLED, "US"),
Order("ORD-005", 800.00, Status.PENDING, "ASIA"),
Order("ORD-006", 8_000.00, Status.SHIPPED, "US")
)
println("=== Order Routing ===")
processBatch(orders)
// ملخص باستخدام نتائج تعبير when
val summary = orders
.filter { it.status != Status.CANCELLED }
.groupBy { routeOrder(it) }
.mapValues { (pipeline, list) -> "${list.size} orders" }
println("\n=== Pipeline Summary ===")
summary.forEach { (pipeline, info) -> println(" $pipeline: $info") }
}
المخرجات:
TEXT
📖 للعرض فقط
=== Order Routing ===
PROCESS: ORD-001 -> REGULAR_SHIPPING [NORMAL]
PROCESS: ORD-002 -> EU_COMPLIANCE_QUEUE [CRITICAL]
PROCESS: ORD-003 -> EXPRESS_SHIPPING [NORMAL]
SKIP: ORD-004 cancelled
PROCESS: ORD-005 -> STANDARD_QUEUE [NORMAL]
PROCESS: ORD-006 -> TRACKING_UPDATE [NORMAL]
=== Pipeline Summary ===
REGULAR_SHIPPING: 1 orders
EU_COMPLIANCE_QUEUE: 1 orders
EXPRESS_SHIPPING: 1 orders
STANDARD_QUEUE: 1 orders
TRACKING_UPDATE: 1 orders
9. أمثلة عملية سريعة
▶ مثال: if كتعبير
KOTLIN
// if تعبير يمكن تعيينه مباشرة
val a = 10
val b = 20
val max = if (a > b) a else b
println("Max: $max")
// if متعدد الفروع كتعبير
val score = 85
val grade = if (score >= 90) "A"
else if (score >= 80) "B"
else if (score >= 70) "C"
else "F"
println("Score $score -> Grade $grade")
// مع كتل (آخر تعبير يُرجع)
val description = if (score >= 60) {
val bonus = score / 10
"Passed with bonus: $bonus"
} else {
"Failed"
}
println(description)
**المخرجات:
TEXT
📖 للعرض فقط
Max: 20
Score 85 -> Grade B
Passed with bonus: 8
▶ مثال: when كتعبير مع أنواع
KOTLIN
// when كتعبير — يفرض الشمول
fun describe(value: Any): String = when (value) {
is String -> "نص بطول ${value.length}: \"$value\""
is Int -> when {
value > 0 -> "عدد صحيح موجب"
value < 0 -> "عدد صحيح سالب"
else -> "صفر"
}
is List<*> -> "قائمة بـ ${value.size} عناصر"
is Map<*, *> -> "خريطة بـ ${value.size} إدخالات"
null -> "قيمة فارغة"
else -> "نوع آخر: ${value::class.simpleName}"
}
println(describe("مرحبا"))
println(describe(42))
println(describe(-5))
println(describe(listOf(1, 2, 3)))
println(describe(null))
println(describe(3.14))
**المخرجات:
TEXT
📖 للعرض فقط
نص بطول 6: "مرحبا"
عدد صحيح موجب
عدد صحيح سالب
قائمة بـ 3 عناصر
قيمة فارغة
نوع آخر: double
▶ مثال: when مع نطاقات وشروط حارس
KOTLIN
fun classifyOrder(total: Double, status: String): String = when {
status == "CANCELLED" -> "ملغي - تخطي"
total > 10_000 -> "VIP - أولوية قصوى"
total > 1_000 && status == "CONFIRMED" -> "أولوية عالية - شحن سريع"
total in 500.0..1_000.0 -> "متوسط - معالجة قياسية"
total < 0 -> "خطأ - مبلغ سالب"
else -> "عادي"
}
println(classifyOrder(15_000.0, "CONFIRMED"))
println(classifyOrder(2_500.0, "CONFIRMED"))
println(classifyOrder(750.0, "PENDING"))
println(classifyOrder(-100.0, "NEW"))
println(classifyOrder(50.0, "CANCELLED"))
println(classifyOrder(50.0, "NEW"))
**المخرجات:
TEXT
📖 للعرض فقط
VIP - أولوية قصوى
أولوية عالية - شحن سريع
متوسط - معالجة قياسية
خطأ - مبلغ سالب
ملغي - تخطي
عادي
▶ مثال: for مع النطاقات والقوائم
KOTLIN
// نطاق مغلق
print("1..5: ")
for (i in 1..5) print("$i ")
println()
// نطاق تنازلي مع step
print("10 downTo 1 step 2: ")
for (i in 10 downTo 1 step 2) print("$i ")
println()
// نصف مفتوح (حتى ولكن لا يشمل)
print("0 until 5: ")
for (i in 0 until 5) print("$i ")
println()
// قائمة
val fruits = listOf("تفاح", "موز", "برتقال")
for (fruit in fruits) println("فاكهة: $fruit")
// مع الفهرس
for ((index, fruit) in fruits.withIndex()) {
println("$index: $fruit")
}
**المخرجات:
TEXT
📖 للعرض فقط
1..5: 1 2 3 4 5
10 downTo 1 step 2: 10 8 6 4 2
0 until 5: 0 1 2 3 4
فاكهة: تفاح
فاكهة: موز
فاكهة: برتقال
0: تفاح
1: موز
2: برتقال
▶ مثال: while و do-while
KOTLIN
// while — فحص شرط قبل التكرار
var countdown = 5
print("Countdown: ")
while (countdown > 0) {
print("$countdown ")
countdown--
}
println("Liftoff!")
// do-while — تنفيذ مرة واحدة على الأقل
var input = 0
var attempts = 0
do {
attempts++
input = (1..10).random()
println("Attempt $attempts: got $input")
} while (input < 5 && attempts < 5)
println("Final: $input after $attempts attempts")
**المخرجات:
TEXT
📖 للعرض فقط
Countdown: 5 4 3 2 1 Liftoff!
Attempt 1: got 7
Final: 7 after 1 attempts
▶ مثال: تصنيفات الحلقات (loop labels)
KOTLIN
// البحث عن عنصر في مصفوفة ثنائية الأبعاد
val matrix = arrayOf(
arrayOf(1, 2, 3),
arrayOf(4, 5, 6),
arrayOf(7, 8, 9)
)
var found = false
var targetValue = 5
outer@ for (i in matrix.indices) {
inner@ for (j in matrix[i].indices) {
if (matrix[i][j] == targetValue) {
println("Found $targetValue at [$i][$j]")
found = true
break@outer // يخرج من كلتا الحلقتين
}
}
}
if (!found) println("$targetValue not found")
// continue@label — تخطي إلى التكرار التالي لحلقة محددة
for (i in 1..5) {
if (i == 3) continue
print("$i ")
}
**المخرجات:
TEXT
📖 للعرض فقط
Found 5 at [1][1]
1 2 4 5
▶ مثال: return@label في lambdas
KOTLIN
val orders = listOf(
"ORD-001" to "CONFIRMED",
"ORD-002" to "CANCELLED",
"ORD-003" to "PENDING",
"ORD-004" to "CONFIRMED"
)
// return@forEach يتخطى فقط هذا العنصر
orders.forEach { (id, status) ->
if (status == "CANCELLED") {
println("SKIP $id (cancelled)")
return@forEach
}
println("PROCESS $id ($status)")
}
// البحث عن أول عنصر مطابق
val firstCancelled = orders.firstOrNull { it.second == "CANCELLED" }
println("First cancelled: ${firstCancelled?.first}")
// takeWhile / dropWhile
val pendingOrders = orders.takeWhile { it.second == "CONFIRMED" }
println("Take while CONFIRMED: $pendingOrders")
val remaining = orders.dropWhile { it.second == "CONFIRMED" }
println("Drop while CONFIRMED: $remaining")
**المخرجات:
TEXT
📖 للعرض فقط
SKIP ORD-002 (cancelled)
PROCESS ORD-001 (CONFIRMED)
PROCESS ORD-003 (PENDING)
PROCESS ORD-004 (CONFIRMED)
First cancelled: ORD-002
Take while CONFIRMED: [(ORD-001, CONFIRMED)]
Drop while CONFIRMED: [(ORD-002, CANCELLED), (ORD-003, PENDING), (ORD-004, CONFIRMED)]
❓ أسئلة شائعة
س هل لدى كوتلن عامل ثلاثي
?:؟ج لا. كوتلن يستخدم
if/else بدلاً من عامل ثلاثي لأن if تعبير — مكافئ وظيفيًا وأكثر قراءة.س ما الفرق بين
when بموضوع وبدون موضوع؟ج
when(x) يطابق قيمة/نوع x مع فحص شمول من المُترجِم؛ when { } تعبيرات شرطية تعسفية ويجب أن تتضمن else.س هل يمكن لحلقة for التكرار على كائنات مخصصة؟
ج نعم، طالما أن الفئة تنفذ
operator fun iterator() التي تُرجع Iterator.س ما هي قيود الإرجاع غير المحلي؟
ج الإرجاع غير المحلي يمكن استخدامه فقط في lambdas للدوال
inline. استخدام الإرجاع غير المحلي في lambda عادي يسبب خطأ ترجمة.س هل ترتيب الفروع مهم في
when؟ج نعم.
when يطابق من الأعلى للأسفل، وأول فرع مُحقَق يفوز. ضع الشروط الأكثر تحديدًا قبل الأكثر عمومية.س كيف أطابق قيمة وشرطًا معًا في
when؟ج استخدم شروط الحارس:
is Order && total > 1000 -> — طابق النوع أولاً، ثم أضف الشرط.📖 ملخص
ifتعبير يمكن تعيينه مباشرة للمتغيرات، مما يحل محل العامل الثلاثي في جافاwhenهو النسخة المطوَّرة منswitch: مطابقة متعددة القيم، النطاقات، الأنواع، شروط الحارس- عندما يُستخدم
whenكتعبير، يفرض المُترجِم الشمول لمنع الفروع المفقودة forيدعم النطاقات، المجموعات، الخرائط، والمكررات المخصصة- التصنيفات مع
break@+continue@تتحكم بدقة في التنقل في الحلقات المتداخلة - إرجاع lambda المحلي
return@forEachمقابل الإرجاع غير المحليreturn
📝 تمارين
- أساسي (⭐): استخدم تعبيرات
ifلتنفيذ دالةmaxOfThreeتُرجع الأكبر من ثلاثة أرقام. تلميح: if متداخلة أو استخدمmaxOf()من المكتبة القياسية - متوسط (⭐⭐): استخدم
whenلتنفيذ تحديد أولوية الطلب: VIP (>10000 دولار) > أولوية عالية (>1000) > عادي، تخطي الطلبات الملغاة. تلميح: شروط حارسwhen - تحدي (⭐⭐⭐): استخدم تصنيفات الحلقات لتنفيذ معالجة طلبات مجمعة: حلقة خارجية على دُفعات العملاء، حلقة داخلية على الطلبات — تخطي دُفعة العميل بالكامل إذا وُجد طلب ملغى. تلميح:
loop@+continue@loop