{"id":"l-sw-1-3","courseId":"swift-essentials","lang":"ar","kind":"lesson","summary":"خزّن المصاريف في المصفوفات والقواميس والمجموعات، وتنقّل بينها بحلقة for-in، واتّخذ القرارات بجملة switch شاملة يفحصها الـ compiler عنك.","html":"<p>المصروف الواحد قيمة. ومصاريف شهر كامل مجموعة (collection). يحتاج Pocket Budget إلى ثلاثة أشكال من المجموعات: قائمة مرتّبة بالمبالغ، وجدول بحث من التصنيف إلى الحدّ الشهري، وكيس من الوسوم الفريدة. تعطيك Swift هذه الثلاثة بالضبط، وكلها محدّدة النوع، فلا يمكن لمصفوفة مبالغ أن تحتوي <code dir=\"ltr\">String</code> بالخطأ.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">المصفوفات: مرتّبة، مفهرسة، محدّدة النوع</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Foundation</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts: [Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12.5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">60</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">append</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">18</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)     </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 4</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])        </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 12.5</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">first</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> as</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Any</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Optional(12.5)</span></span></code></pre></div>\n<p>تُقرأ <code dir=\"ltr\">[Decimal]</code> «مصفوفة من <code dir=\"ltr\">Decimal</code>». الفهارس تبدأ من 0. لاحظ الفرق بين <code dir=\"ltr\">amounts[0]</code> و<code dir=\"ltr\">amounts.first</code>: الوصول بالفهرس يثق بك ويُسقط التطبيق مع “Index out of range” إذا كانت المصفوفة فارغة، بينما <code dir=\"ltr\">first</code> يعيد optional ويتيح لك التعامل مع الحالة الفارغة بالأدوات التي تعلّمتها في الدرس السابق.</p>\n<p>في أغلب الأحيان لا تحتاج إلى الفهارس أصلًا. حلقة <code dir=\"ltr\">for-in</code> تزور كل عنصر:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> total: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(total)             </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 94.75</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (index, amount) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">enumerated</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">index </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">. </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>تعطيك <code dir=\"ltr\">enumerated()</code> أزواجًا من الموضع والقيمة، وهذه هي الطريقة الآمنة لترقيم الصفوف. والنطاقات تعمل مع <code dir=\"ltr\">for-in</code> أيضًا، بنوعين:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> day </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">30</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { }               </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// closed range: 1 through 30</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> i </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { }      </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// half-open: stops before count</span></span></code></pre></div>\n<p>النطاق المغلق يشمل حدّه الأعلى؛ أما النطاق نصف المفتوح فيتوقّف قبله بواحد، وهذا بالضبط ما تحتاجه فهارس المصفوفات.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">القواميس: بحث قد لا يجد شيئًا</h2>\n<p>القاموس (dictionary) يربط مفاتيح بقيم. يحتفظ Pocket Budget بحدّ شهري لكل تصنيف:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 120</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> foodLimit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]          </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Decimal?, Optional(300)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> funLimit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">       // Decimal, 0</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">spent[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">default</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">          // creates \"Fun\": 15</span></span></code></pre></div>\n<p>كل بحث يعيد optional، لأن المفتاح قد لا يكون موجودًا. إنها فكرة الأمان نفسها مرة أخرى، لكنها هذه المرة مبنية داخل المجموعة. والصيغة <code dir=\"ltr\">default:</code> هي الطريقة المعتادة لحساب المجاميع التراكمية: تقرأ القيمة الموجودة أو تبدأ من القيمة الافتراضية التي حدّدتها، ثم تكتب النتيجة مرة أخرى.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>توقّع أن يحتفظ القاموس بترتيبه</span></p>\n<p><code dir=\"ltr\">for (category, limit) in limits</code> تزور الأزواج بترتيب قد يتغيّر من تشغيل إلى آخر. إن احتاجت الواجهة ترتيبًا ثابتًا، فرتّب أولًا: <code dir=\"ltr\">for category in limits.keys.sorted()</code>.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">المجموعات: قيم فريدة</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> tags: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Set</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"work\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"travel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">insert</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"work\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)          </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// already there, nothing changes</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 2</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">contains</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"travel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// true</span></span></code></pre></div>\n<p>المجموعة (Set) لا ترتيب فيها ولا تكرار، ويبقى <code dir=\"ltr\">contains</code> سريعًا مهما كثرت عناصرها. استخدمها للوسوم، والفلاتر المختارة، وفحوصات «هل رأيت هذا المعرّف من قبل؟».</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">اختيار المجموعة المناسبة</h2>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"جدول قابل للتمرير\" tabindex=\"0\"><table><thead>\n<tr>\n<th>تحتاج إلى</th>\n<th>استخدم</th>\n<th>مثال من Pocket Budget</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>ترتيب، والتكرار مسموح، والوصول بالموضع</td>\n<td>مصفوفة (Array)</td>\n<td>مصاريف هذا الشهر، الأحدث أولًا</td>\n</tr>\n<tr>\n<td>البحث عن قيمة بمفتاح</td>\n<td>قاموس (Dictionary)</td>\n<td>الحدّ الشهري لكل تصنيف</td>\n</tr>\n<tr>\n<td>العضوية والتفرّد، والترتيب لا يهم</td>\n<td>مجموعة (Set)</td>\n<td>الوسوم على مصروف واحد</td>\n</tr>\n</tbody>\n</table></div><p>إن تردّدت، فابدأ بمصفوفة. إنها المجموعة التي تعرضها قوائم SwiftUI، وأسهلها قراءةً في الـ debugger. انتقل إلى القاموس حين تجد نفسك تبحث في مصفوفة عن «العنصر الذي يحمل هذا الاسم»، وإلى المجموعة حين تجد نفسك تفحص التكرار قبل كل إضافة.</p>\n<p>المجموعات الثلاث كلها قيم، لا كائنات مشتركة. <code dir=\"ltr\">var copy = amounts</code> تعطيك مصفوفة مستقلّة: الإضافة إلى <code dir=\"ltr\">copy</code> لا تمسّ <code dir=\"ltr\">amounts</code>. لهذا السلوك اسم، سلوك القيمة (value semantics)، وله درس خاص في القسم التالي لأنه يحدّد طريقة تصميمك لكل نوع في نموذج بياناتك.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">switch: شاملة بالتصميم</h2>\n<p>جملة <code dir=\"ltr\">switch</code> في Swift أكثر بكثير من سلسلة فحوصات مساواة. فهي تطابق النطاقات، وتربط القيم، وتضيف الشروط، والـ compiler يصرّ على معالجة كل قيمة ممكنة. هكذا يختار Pocket Budget رسالة الحالة بناءً على النسبة المستهلكة من الميزانية:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">BudgetStatus.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> status</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">percentUsed</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Int</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> percentUsed {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Check your numbers\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">50</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Plenty left\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 50</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">90</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"On track\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 90</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">100</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Nearly at your limit\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    default:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Over budget\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">status</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">percentUsed</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">95</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Nearly at your limit</span></span></code></pre></div>\n<p>هناك فرقان عن لغات عائلة C. أولًا، لا يوجد <code dir=\"ltr\">break</code> ولا انتقال عرضي إلى الحالة التالية: متى طابقت حالة، انتهت الـ switch. ثانيًا، احذف <code dir=\"ltr\">default</code> وستفشل الترجمة مع “switch must be exhaustive”، لأن النوع <code dir=\"ltr\">Int</code> له قيم لا تغطّيها حالاتك. يبدو هذا الخطأ مزعجًا مع الأعداد الصحيحة. لكن مع الـ enums، في القسم التالي، يصبح أنفع خطأ في اللغة: أضف حالة جديدة إلى نموذجك، وسيعرض لك الـ compiler كل <code dir=\"ltr\">switch</code> نسيت تحديثها.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 150\" role=\"img\" aria-labelledby=\"l-sw-1-3-t1\"><defs><marker id=\"arrow-l-sw-1-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-sw-1-3-t1\">خط أعداد مقسوم إلى خمس حالات: أقل من 0، ومن 0 حتى ما قبل 50، ومن 50 حتى ما قبل 90، ومن 90 حتى 100، وdefault لكل ما فوق 100. معًا تغطّي كل عدد صحيح.</title>\n  <rect class=\"d-box-warn\" x=\"10\" y=\"40\" width=\"110\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"65\" y=\"70\" text-anchor=\"middle\">..&lt;0</text>\n  <rect class=\"d-box-success\" x=\"130\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"195\" y=\"70\" text-anchor=\"middle\">0..&lt;50</text>\n  <rect class=\"d-box-accent\" x=\"270\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"335\" y=\"70\" text-anchor=\"middle\">50..&lt;90</text>\n  <rect class=\"d-box-primary\" x=\"410\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"475\" y=\"70\" text-anchor=\"middle\">90...100</text>\n  <rect class=\"d-box-warn\" x=\"550\" y=\"40\" width=\"120\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"610\" y=\"70\" text-anchor=\"middle\">default</text>\n  <text class=\"d-label-muted\" x=\"340\" y=\"125\" text-anchor=\"middle\">النطاقات لا تتداخل، والحالة default تلتقط كل Int آخر</text>\n</svg><figcaption>كيف تغطّي نطاقات الحالة في Pocket Budget كل قيمة Int</figcaption></figure>\n<p>يمكن للحالات أيضًا أن تربط القيمة المطابَقة وتختبرها بـ <code dir=\"ltr\">where</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 10</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Nothing spent yet\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Over by </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">default:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Within budget\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>وفي Swift 5.9 صار ممكنًا استخدام <code dir=\"ltr\">switch</code> و<code dir=\"ltr\">if</code> كتعبيرات، فتعمل الصيغة <code dir=\"ltr\">let label = switch percentUsed { … }</code> حين تنتج كل حالة قيمة واحدة. استخدم الصيغة الأوضح قراءةً؛ قاعدة الشمول واحدة في الحالتين.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>رتّب حالاتك من الأضيق إلى الأعم</span></p>\n<p>تُجرَّب الحالات من الأعلى إلى الأسفل وأول تطابق يفوز. ضع الحالات الضيّقة مثل <code dir=\"ltr\">case 0:</code> قبل الواسعة مثل <code dir=\"ltr\">case let amount where amount &gt; limit:</code>.</p>\n</aside>\n<p>صار بإمكانك الآن أن تحمل بيانات شهر كامل وتتّخذ قرارات بشأنها. حلقات التكرار في هذا الدرس تعمل، لكنها مكتوبة بالطريقة الطويلة. بعد ذلك ستجمع المنطق في دوال، وتستبدل معظم هذه الحلقات بـ closures مثل <code dir=\"ltr\">filter</code> و<code dir=\"ltr\">map</code> و<code dir=\"ltr\">reduce</code>.</p>\n","toc":[{"id":"sec-1","text":"المصفوفات: مرتّبة، مفهرسة، محدّدة النوع","level":2},{"id":"sec-2","text":"القواميس: بحث قد لا يجد شيئًا","level":2},{"id":"sec-3","text":"المجموعات: قيم فريدة","level":2},{"id":"sec-4","text":"اختيار المجموعة المناسبة","level":2},{"id":"sec-5","text":"switch: شاملة بالتصميم","level":2}],"takeaways":["المصفوفة مرتّبة وفهارسها تبدأ من 0؛ والقراءة بعد نهايتها تُسقط التطبيق، لذلك فضّل <code dir=\"ltr\">first</code> و<code dir=\"ltr\">last</code> و<code dir=\"ltr\">for-in</code> على الفهارس اليدوية.","البحث في القاموس يعيد دائمًا optional، لأن المفتاح قد لا يكون موجودًا؛ والصيغة <code dir=\"ltr\">dict[key, default: 0]</code> تعطيك قيمة بديلة.","المجموعة (Set) تخزّن قيمًا فريدة، وفحص <code dir=\"ltr\">contains</code> فيها سريع، ولا ترتيب لعناصرها.","جملة <code dir=\"ltr\">switch</code> في Swift يجب أن تغطّي كل قيمة ممكنة، ولا تنتقل ضمنيًا إلى الحالة التالية، ويمكنها مطابقة النطاقات وشروط <code dir=\"ltr\">where</code>."],"further":[{"title":"Collection Types","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/collectiontypes/"},{"title":"Control Flow","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/"}],"quiz":[{"q":"<p>لديك <code dir=\"ltr\">let limits = [&quot;Food&quot;: 300]</code>. ما نوع <code dir=\"ltr\">limits[&quot;Fun&quot;]</code>؟</p>","options":[{"text":"<code dir=\"ltr\">Int</code>، وقيمته 0","why":"لا تخترع Swift قيمة لمفتاح غير موجود. أنت تطلب القيمة الافتراضية صراحةً باستخدام <code dir=\"ltr\">default:</code>."},{"text":"<code dir=\"ltr\">Int?</code>، وقيمته <code dir=\"ltr\">nil</code>","why":"صحيح. كل بحث في قاموس يعيد optional، لأن أي مفتاح قد يكون غائبًا."},{"text":"يتعطّل التطبيق لأن المفتاح غير موجود.","why":"هذا ما يحدث مع المصفوفات عند فهرس خاطئ. أما القواميس فتعيد <code dir=\"ltr\">nil</code> للمفتاح الغائب."}],"answer":1},{"q":"<p>كتبت <code dir=\"ltr\">switch</code> على تصنيف من النوع <code dir=\"ltr\">String</code>، ووضعت حالتين فقط لـ “Food” و&quot;Transport&quot;. ماذا يقول الـ compiler؟</p>","options":[{"text":"لا شيء؛ النصوص غير المطابقة تمرّ بصمت.","why":"لا يوجد في Swift مرور صامت للقيم غير المطابقة. يجب أن تصل كل قيمة إلى حالة ما."},{"text":"يحذّرك من أن الـ switch قد يكون بطيئًا.","why":"الأداء ليس المشكلة. الشمول خطأ صريح يوقف الترجمة، لا تحذير."},{"text":"“Switch must be exhaustive”، فتضيف حالة <code dir=\"ltr\">default:</code>.","why":"صحيح. للنوع <code dir=\"ltr\">String</code> عدد لا نهائي من القيم، فلا يغطّي الباقي إلا <code dir=\"ltr\">default</code>."}],"answer":2},{"q":"<p>أيّ مجموعة تناسب «الوسوم التي أضافها المستخدم إلى مصروف، دون تكرار»؟</p>","options":[{"text":"<code dir=\"ltr\">Set&lt;String&gt;</code>","why":"صحيح. المجموعة تتجاهل الإدخال المكرّر وتجيب عن <code dir=\"ltr\">contains</code> بسرعة؛ وترتيب الوسوم لا يهم."},{"text":"<code dir=\"ltr\">[String]</code>","why":"المصفوفة تسمح بالتكرار، فستضطر إلى الفحص قبل كل إضافة."},{"text":"<code dir=\"ltr\">[String: Bool]</code>","why":"تعمل، لكنها مجموعة متنكّرة. استخدم النوع الذي يقول ما تعنيه."},{"text":"<code dir=\"ltr\">[Int: String]</code>","why":"المفاتيح الرقمية لا تضيف شيئًا هنا؛ ستعيد بناء مصفوفة بخطوات إضافية."}],"answer":0},{"q":"<p>لديك <code dir=\"ltr\">let amounts: [Decimal] = []</code>. ماذا يفعل <code dir=\"ltr\">amounts[0]</code> وقت التشغيل؟</p>","options":[{"text":"يعيد <code dir=\"ltr\">nil</code>.","why":"هذا ما يفعله <code dir=\"ltr\">amounts.first</code>. أما الوصول بالفهرس في المصفوفة فلا يعيد optional أبدًا."},{"text":"يتعطّل التطبيق مع الرسالة “Index out of range”.","why":"صحيح. الوصول بالفهرس يثق بك؛ والمصفوفة الفارغة ليس فيها فهرس 0."},{"text":"يعيد 0.","why":"المصفوفات لا تملأ الفراغات بقيم افتراضية."}],"answer":1}],"exercise":{"kind":"choice","options":["a","b","c","d"],"correct":["c"],"title":"توقّع التقرير الشهري","prompt":"<p>اقرأ هذا المقطع من التقرير الشهري في Pocket Budget وتوقّع بالضبط ما يطبعه. مرّ على كل تصنيف بالترتيب، وتتبّع ما يعيده كل بحث في القاموسين.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 120</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">spent[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">default</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> category </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent[category] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[category] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: nothing yet\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: over by </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    default:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: ok\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","hints":["بعد السطر 3 يحتوي <code dir=\"ltr\">spent</code> على مفتاحين. ما هما، وما قيمتاهما؟","المفتاح الغائب مع <code dir=\"ltr\">?? 0</code> يعطي 0. وهذا ينطبق على <code dir=\"ltr\">spent</code> و<code dir=\"ltr\">limits</code> معًا.","التصنيف “Fun” ليس له حدّ أصلًا، فحدّه 0. هل 15 أكبر من 0؟"],"explanation":"<p>السطر <code dir=\"ltr\">spent[&quot;Fun&quot;, default: 0] += 15</code> يضيف مدخلًا باسم “Fun”، فيصبح <code dir=\"ltr\">spent</code> هو <code dir=\"ltr\">[&quot;Food&quot;: 280, &quot;Fun&quot;: 15]</code>.</p>\n<ul>\n<li><strong>Food</strong>: المستهلك 280 والحدّ 300. ليس 0 ولا يتجاوز الحدّ، فتطبع <code dir=\"ltr\">default</code> العبارة “Food: ok”.</li>\n<li><strong>Transport</strong>: لا مدخل له في <code dir=\"ltr\">spent</code>، فالمستهلك 0 وتطبع الحالة الأولى “Transport: nothing yet”.</li>\n<li><strong>Fun</strong>: المستهلك 15 ولا حدّ له، فتكون <code dir=\"ltr\">limits[&quot;Fun&quot;] ?? 0</code> مساوية لـ 0. و15 &gt; 0 فيُطبع “Fun: over by 15”.</li>\n</ul>\n<p>السطر الأخير سؤال منتج حقيقي متنكّر: هل يُعدّ التصنيف الذي لا حدّ له «متجاوزًا»؟ الكود يقول نعم لأن <code dir=\"ltr\">?? 0</code> اختار هذه القيمة الافتراضية. القيم الافتراضية قرارات.</p>\n","checkLabels":{},"optionText":{"a":{"text":"Food: ok / Transport: ok / Fun: ok","why":"لم يُنفَق شيء على Transport، فيطابق <code dir=\"ltr\">case 0</code> أولًا. وليس لـ Fun حدّ، والكود يعامل ذلك على أنه 0."},"b":{"text":"Food: ok / Transport: nothing yet / Fun: nothing yet","why":"الصيغة <code dir=\"ltr\">default:</code> في السطر 3 كتبت 15 في “Fun”، فلم تعد قيمته 0."},"c":{"text":"Food: ok / Transport: nothing yet / Fun: over by 15","why":"صحيح. المفتاح الغائب لـ Transport يصبح 0، والحدّ الغائب لـ Fun يصبح 0، فتُحسب 15 تجاوزًا."},"d":{"text":"Food: over by 20 / Transport: nothing yet / Fun: over by 15","why":"280 أقل من حدّ Food البالغ 300، فلا تطابق الحالة <code dir=\"ltr\">where amount &gt; limit</code>."}}},"words":639,"readMinutes":4}