Kotlin: شرح تدفق التحكم في كوتلن

آخر تحديث: 2026-08-26

تدفق التحكم في كوتلن ليس مجرد تحكم في التدفق — if وwhen هما تعبيران بقيم إرجاع، مما يجعل منطق توجيه طلبات تشارلي آمنًا وموجزًا.

1. ما ستتعلمه


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) مخطط توجيه حالة الطلب

100%
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 -> — طابق النوع أولاً، ثم أضف الشرط.

📖 ملخص


📝 تمارين

  1. أساسي (⭐): استخدم تعبيرات if لتنفيذ دالة maxOfThree تُرجع الأكبر من ثلاثة أرقام. تلميح: if متداخلة أو استخدم maxOf() من المكتبة القياسية
  2. متوسط (⭐⭐): استخدم when لتنفيذ تحديد أولوية الطلب: VIP (>10000 دولار) > أولوية عالية (>1000) > عادي، تخطي الطلبات الملغاة. تلميح: شروط حارس when
  3. تحدي (⭐⭐⭐): استخدم تصنيفات الحلقات لتنفيذ معالجة طلبات مجمعة: حلقة خارجية على دُفعات العملاء، حلقة داخلية على الطلبات — تخطي دُفعة العميل بالكامل إذا وُجد طلب ملغى. تلميح: loop@ + continue@loop

← السابق | التالي ←

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%