<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; Go</title><link>https://academy.hsoub.com/programming/go/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; Go</description><language>ar</language><item><title>&#x627;&#x644;&#x645;&#x624;&#x634;&#x631;&#x627;&#x62A; Pointers &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D9%85%D8%A4%D8%B4%D8%B1%D8%A7%D8%AA-pointers-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1975/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_05/-Pointers----Go.png.399865574004ba5167d8dfc896bafe22.png" /></p>
<p>
	المؤشّر هو عنوان يشير إلى موقع في الذاكرة، وتُستخدم المؤشرات عادةً للسماح للدوالّ أو <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-data-structures/" rel="">هياكل البيانات</a> بالحصول على معلومات عن الذاكرة وتعديلها دون الحاجة إلى نسخ الذاكرة المشار إليها، والمؤشّرات قابلة للاستخدام سواءٌ مع الأنواع الأوليّة (المٌضمّنة) أو الأنواع التي يعرّفها المستخدم.
</p>

<p>
	تتضمن البرامج المكتوبة بلغة جو عادةً دوالًا وتوابعًا Methods نمرر لها بيانات مثل وسطاء، ونحتاج أحيانًا إلى إنشاء نسخة محلية من تلك البيانات بحيث تظل النسخة الأصلية من البيانات دون تغيير. مثلًا، لو كان لديك برنامج يمثّل مصرفًا bank، وتريد أن يُظهر هذا البرنامج التغيرات التي تطرأ على رصيد المستخدم تبعًا للخطة التوفيرية التي يختارها، فهنا قد تحتاج إلى بناء دالة تنجز هذا الأمر من خلال تمرير الرصيد الحالي للمستخدم إضافةً إلى الخطة التي يريدها. لا نريد هنا تغيير الرصيد الأساسي وإنما نريد فقط إظهار التعديل الذي سيطرأ على الرصيد، وبالتالي يجب أن نأخذ نسخةً من رصيد المستخدم مثل وسيط للدالة ونعدّل على هذه النسخة. تسمى هذه النسخة نسخةً محلية، وندعو عملية التمرير هذه "التمرير بالقيمة passing by value" لأننا لانرسل المتغير نفسه وإنما قيمته فقط.
</p>

<p>
	هناك حالات أخرى قد تحتاج فيها إلى تعديل البيانات الأصلية؛ بمعنى آخر قد نحتاج إلى تغيير قيمة المتغير الأصلي مباشرةً من خلال الدالة، فمثلًا، عندما يودع المستخدم رصيدًا إضافيًّا في حسابه، فهنا تحتاج إلى جعل الدالة قادرةً على تعديل قيمة الرصيد الأصلي وليس نسخةً منه (نحن نريد إضافة مال إلى رصيده السابق). ليس ضروريًا هنا تمرير البيانات الفعلية إلى الدالة، إذ يمكنك ببساطة إخبار الدالة بالمكان الذي توجد به البيانات في الذاكرة من خلال "مؤشر" يحمل عنوان البيانات الموجودة في الذاكرة. لا يحمل المؤشر القيمة، وإنما فقط عنوان أو مكان وجود القيمة، وتتمكن الدالة من خلال هذا المؤشر من التعديل على البيانات الأصلية مباشرةً. يسمى هذا "التمرير بالمرجع passing by reference"، لأن قيمة المتغير لا تُمرّر إلى الدالة، بل إلى موقعها فقط.
</p>

<p>
	سننشئ في هذا المقال المؤشرات ونستخدمها لمشاركة الوصول إلى الذاكرة المُخصصة لمتغير ما.
</p>

<h2>
	تعريف واستخدام المؤشرات
</h2>

<p>
	يوجد عنصرا صيغة مختلفان يختصان باستخدام مؤشّر لمتغيرٍ variable ما، وهما: معامل العنونة Address-of operator وهو "&amp;" الذي يعيد عنوان المتغيّر الذي يوضع أمامه في الذاكرة، ومعامل التحصيل Dereference، وهو "*" الذي يعيد قيمة المتغير الموجود في العنوان المحدّد بواسطة عامله.
</p>

<p>
	<strong>ملاحظة</strong>: يُستخدم رمز النجمة * أيضًا للتصريح عن مؤشّر لمجرد التوضيح بأنه مؤشر، ولا ينبغي أن تخلط بينه وبين عامل التحصيل الذي يُستخدم للحصول على القيمة الموجودة في عنوان محدّد، فهما شيئان مختلفان مُمثّلان بنفس الرمز.
</p>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_8" style=""><span class="pln">var myPointer </span><span class="pun">*</span><span class="typ">int32</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">someint</span></pre>

<p>
	صرّحنا هنا عن متغير يُسمّى <code>myPointer</code> يُمثّل مؤشرًا لمتغير من نوع العدد الصحيح <code>int32</code>، وهيأنا المؤشر بعنوان <code>someint</code>، فالمؤشر هنا يحمل عنوان المتغير <code>int32</code> وليس قيمته.
</p>

<p>
	دعنا نلقي الآن نظرةً على مؤشر لسلسلة، إذ تُصرّح الشيفرة التالية عن متغير يُمثّل سلسلة ومتغير آخر يُمثّل مؤشرًا على تلك السلسلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_10" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pln">
    var pointer </span><span class="pun">*</span><span class="pln">string </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">creature

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature ="</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"pointer ="</span><span class="pun">,</span><span class="pln"> pointer</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	شغّل البرنامج بالأمر التالي:
</p>

<pre class="ipsCode">$ go run main.go
</pre>

<p>
	سيطبع البرنامج عند تشغيله قيمة المتغير إضافةً إلى عنوان تخزين المتغير (عنوان المؤشر). عنوان الذاكرة هو سلسلة أرقام مكتوبة بنظام العد السداسي عشري لأسباب عتادية وبرمجية لا تهمنا الآن، وطبعنا القيم هنا للتوضيح فقط. ستلاحظ تغيُّر العنوان المطبوع في كل مرة تُشغّل فيها البرنامج، لأنه يُهيّأ من جديد وتأخذ فيه المتغيرات أماكن غير محددة في الذاكرة؛ فكل برنامج ينشئ مساحته الخاصة من الذاكرة عند تشغيله. إذًا، سيكون خرج الشيفرة السابقة مختلفًا لديك عند تشغيله:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_12" style=""><span class="pln">creature </span><span class="pun">=</span><span class="pln"> shark
pointer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0xc0000721e0</span></pre>

<p>
	عرّفنا المتغير الأول <code>creature</code> من النوع <code>string</code> وهيّأناه بالقيمة <code>shark</code>. أنشأنا أيضًا متغيرًا يُسمّى <code>pointer</code> يُمثّل مؤشرًا على عنوان متغير سلسلة نصية، أي يحمل عنوان متغير نوعه <code>string</code>، وهيّأناه بعنوان السلسلة النصية المُمثّلة بالمتغير <code>creature</code> وذلك من خلال وضع المعامل "&amp;" قبل اسمه.
</p>

<p>
	إذًا، سيحمل <code>pointer</code> عنوان الذاكرة التي يوجد بها <code>creature</code> وليس قيمته. هذا هو السبب وراء الحصول على القيمة 0xc0000721e0 عندما طبعنا قيمة المؤشر، وهو عنوان مكان تخزين متغير <code>creature</code> حاليًا في ذاكرة الحاسب.
</p>

<p>
	يمكنك الوصول إلى قيمة المتغير مباشرةً من خلال نفس المؤشر باستخدام معامل التحصيل "*" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_14" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pln">
    var pointer </span><span class="pun">*</span><span class="pln">string </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">creature

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature ="</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"pointer ="</span><span class="pun">,</span><span class="pln"> pointer</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"*pointer ="</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pointer</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ويكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_16" style=""><span class="pln">creature </span><span class="pun">=</span><span class="pln"> shark
pointer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0xc000010200</span><span class="pln">
</span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> shark</span></pre>

<p>
	يُمثّل السطر الإضافي المطبوع ماتحدّثنا عنه (الوصول لقيمة المتغير من خلال المؤشر). نسمي ذلك "التحصيل" إشارةً إلى الوصول لقيمة المتغير من خلال عنوانه. يمكننا استخدام هذه الخاصية أيضًا في تعديل قيمة المتغير المُشار إليه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_18" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pln">
    var pointer </span><span class="pun">*</span><span class="pln">string </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">creature

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature ="</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"pointer ="</span><span class="pun">,</span><span class="pln"> pointer</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"*pointer ="</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pointer</span><span class="pun">)</span><span class="pln">

    </span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"*pointer ="</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pointer</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_20" style=""><span class="pln">creature </span><span class="pun">=</span><span class="pln"> shark
pointer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0xc000094040</span><span class="pln">
</span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> shark
</span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> jellyfish</span></pre>

<p>
	لاحظ أننا في السطر <code>"pointer = "jellyfish*</code> وضعنا معامل التحصيل * قبل المؤشر للإشارة إلى أننا نريد تعديل القيمة التي يُشير إلى عنوانها المؤشر. أسندنا القيمة "jellyfish" إلى موقع الذاكرة التي يُِشير لها <code>pointer</code>، وهذا يُكافئ تعديل قيمة المتغير <code>creature</code>. لاحظ أنه عند طباعة القيمة التي يُشير لها المؤشر سنحصل على القيمة الجديدة.
</p>

<p>
	كما ذكرنا؛ فهذا يُكافئ تعديل قيمة المتغير <code>creature</code>، وبالتالي لو حاولنا طباعة قيمة المتغير <code>creature</code> سنحصل على القيمة "jellyfish" لأننا نُعدّل على الموقع الذاكري نفسه. سنضيف الآن سطرًا يطبع قيمة المتغير <code>creature</code> إلى الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_22" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pln">
    var pointer </span><span class="pun">*</span><span class="pln">string </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">creature

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature ="</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"pointer ="</span><span class="pun">,</span><span class="pln"> pointer</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"*pointer ="</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pointer</span><span class="pun">)</span><span class="pln">

    </span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"*pointer ="</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pointer</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature ="</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وسيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_24" style=""><span class="pln">creature </span><span class="pun">=</span><span class="pln"> shark
pointer </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0xc000010200</span><span class="pln">
</span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> shark
</span><span class="pun">*</span><span class="pln">pointer </span><span class="pun">=</span><span class="pln"> jellyfish
creature </span><span class="pun">=</span><span class="pln"> jellyfish</span></pre>

<p>
	يهدف كل ما تعلمته حتى الآن إلى توضيح فكرة المؤشرات في لغة جو وليس حالات الاستخدام الشائعة لها، فهي تُستخدم غالبًا عند تعريف وسطاء الدوال والقيم المُعادة منها أو عند تعريف التوابع مع أنواع مخصصة. دعنا الآن نلقي نظرةً على كيفية استخدام المؤشرات مع الدوال لمشاركة الوصول إلى المتغيرات.
</p>

<p>
	ضع في الحسبان أننا نطبع قيمة المؤشر لتوضيح أنه مؤشر، فلن تستخدم عمليًا قيمة المؤشر إلا للإشارة إلى القيمة الأساسية لاستردادها أو تعديلها.
</p>

<h2>
	مستقبلات مؤشرات الدوال
</h2>

<p>
	عند كتابة دالة، يمكنك تعريف بعض الوسطاء لكي تُمررهم لها إما بالقيمة أو بالمرجع؛ فعندما تُمرر وسيطًا ما بالقيمة، فهذا يعني أنك تُرسل نسخةً مُستقلة من قيمة هذا الوسيط إلى الدالة، وبالتالي فإن أي تغيير يحدث لهذه النسخة لن يؤثر على النسخة الأساسية من البيانات، لأن كل التعديلات ستجري على نُسخة من البيانات؛ أما عندما تُمرر وسيطًا بالمرجع، فهذا يعني أنك تُرسل مؤشرًا يحمل عنوان ذلك الوسيط -أي مكان تواجد البيانات في الذاكرة- إلى الدالة، وبالتالي أصبح لديك القدرة على الوصول إلى البيانات الأصلية من داخل الدالة والتعديل عليها مباشرةً.
</p>

<p>
	يمكنك الاطلاع على المقالة التالية إذا أردت معرفة المزيد عن <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D9%88%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1962/" rel="">الدوال وطرق استدعائها في لغة جو</a>.
</p>

<p>
	يمكنك طبعًا تمرير أي وسيط بالطريقة التي تُريدها (بالقيمة أو بالمرجع)، فهذا يعتمد على ما تحتاجه؛ فإذا كنت تريد أن تُعدّل الدالة على البيانات الأصلية نُمرر الوسيط بالمرجع وإلا بالقيمة.
</p>

<p>
	لمعرفة الفرق بدقة، دعنا أولًا نلقي نظرة على دالة تمرّر وسيطًا بالقيمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_26" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="typ">Creature</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Creature</span><span class="pun">{</span><span class="typ">Species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    changeCreature</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"3) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func changeCreature</span><span class="pun">(</span><span class="pln">creature </span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    creature</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ويكون الخرج على النحو التالي:
</p>

<pre class="ipsCode">1) {Species:shark}
2) {Species:jellyfish}
3) {Species:shark}
</pre>

<p>
	أنشأنا بدايةً نوع بيانات مخصص أسميناه <code>Creature</code>، يحتوي على حقل واحد يُسمى <code>Species</code> من نوع <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">سلسلة نصية</a> <code>string</code>، وأنشأنا داخل الدالة الرئيسية <code>main</code> متغير من النوع <code>Creature</code> اسمه <code>creature</code> وأسندنا السلسلة <code>shark</code> إلى الحقل <code>Species</code>. بعد ذلك طبعنا المتغير <code>creature</code> لإظهار القيمة التي يتضمنها في الوقت الحالي، ثم مرّرنا المتغير <code>creature</code> (تمرير بالقيمة أي نُسخة) إلى الدالة <code>changeCreature</code> والتي بدورها تطبع قيمة المتغير المُمرر لها بعد إسناد السلسلة "jellyfish" إلى الحقل <code>Species</code> (هنا نطبعه من داخل الدالة أي محليًّا). بعد ذلك طبعنا قيمة المتغير <code>creature</code> مرةً أخرى (خارج الدالة السابقة).
</p>

<p>
	لاحظ أنه يوجد لدينا ثلاث تعليمات طباعة؛ جرى السطر الأول والثالث من الخرج ضمن نطاق الدالة <code>main</code> بينما كان السطر الثاني ضمن نطاق الدالة <code>changeCreature</code>. لاحظ أيضًا أنه في البداية كانت قيمة المتغير <code>creature</code> هي "shark" وبالتالي عند تنفيذ تعليمة الطباعة الأولى سيطبع:
</p>

<pre class="ipsCode">(1) {Species:shark}
</pre>

<p>
	أما تعليمة الطباعة في السطر الثاني والموجودة ضمن نطاق الدالة <code>changeCreature</code>، فسنلاحظ أنها ستطبع القيمة:
</p>

<pre class="ipsCode">(2) {Species:jellyfish}
</pre>

<p>
	لأننا عدلنا قيمة المتغير، أما في التعليمة الثالثة فقد يُخطئ البعض ويعتقد أنها ستطبع نفس القيمة التي طبعتها تعليمة السطر الثاني، لكن هذا لا يحدث لأن التعديل بقي محليًّا ضمن نطاق الدالة <code>changeCreature</code>، أي حدث التعديل على نسخة من المتغير <code>creature</code> وبالتالي لا ينتقل التعديل إلى المتغير الأساسي. إذًا سيكون خرج تعليمات الطباعة للسطرين الأول والثالث متطابق.
</p>

<p>
	سنأخذ الآن نفس المثال، لكن سنغيّر عملية التمرير إلى الدالة <code>changeCreature</code> لتصبح تمرير بالمرجع، وذلك من خلال تغيير النوع من <code>creature</code> إلى مؤشر باستخدام المعامل "*"، فبدلًا من تمرير <code>creature</code>، سنمرّر الآن مؤشرًا إلى <code>creature</code> أو <code>creature*</code>. كان <code>creature</code> في المثال السابق من النوع <code>struct</code> ويحتوي قيمة الحقل <code>Species</code> وهي "shark"، أما <code>creature*</code> فهو مؤشر وليس <code>struct</code>، وبالتالي قيمته هي موقع الذاكرة وهذا ما مرّرناه إلى الدالة <code>()changeCreature</code>. لاحظ أننا نضع المعامل "&amp;" عند تمرير المتغير <code>creature</code> إلى الدالة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_28" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="typ">Creature</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Creature</span><span class="pun">{</span><span class="typ">Species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    changeCreature</span><span class="pun">(&amp;</span><span class="pln">creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"3) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func changeCreature</span><span class="pun">(</span><span class="pln">creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    creature</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستحصل عند تنفيذ الشيفرة السابقة على الخرج التالي:
</p>

<pre class="ipsCode">1) {Species:shark}
2) &amp;{Species:jellyfish}
3) {Species:jellyfish}
</pre>

<p>
	قد تبدو الأمور واضحة الآن، فعندما مرّرنا المتغير <code>creature</code> إلى الدالة <code>changeCreature</code>، كان التمرير بالمرجع، وبالتالي أي تغيير يطرأ على المتغير <code>creature</code> (وهو تغيير قيمة الحقل <code>Species</code> إلى "jellyfish") داخل هذه الدالة، سيكون مُطبّقًا على المتغير الأصلي نفسه الموجود ضمن الدالة <code>main</code> لأننا نُعدّل على نفس الموقع في الذاكرة، وبالتالي ستكون قيمة الخرج لتعليمات الطباعة 2 و 3 مُتطابقة.
</p>

<p>
	قد لا يكون لدينا في بعض الأحيان قيمة مُعرّفة للمؤشر، وهذا قد يحدث لأسباب كثيرة منها ما هو متوقع ومنها لا، وبالتالي قد يسبب لك <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%86%D9%87%D9%8A%D8%A7%D8%B1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1901/" rel="">حالات هلع panic</a> في البرنامج. دعنا نلقي نظرةً على كيفية حدوث ذلك وكيفية التخطيط لتلك المشكلة المحتملة.
</p>

<h2>
	التأشير إلى اللاشيء Nil
</h2>

<p>
	القيمة الافتراضية لجميع المتغيرات في لغة جو هي الصفر، وهذا الكلام ينطبق أيضًا على المؤشرات. لدى التصريح عن مؤشر بنوعٍ ما ولكن دون أي قيمة مُسندة، ستكون القيمة الصفرية الافتراضية هي <code>nil</code>. الصفر هنا مفهوم متعلق بالنوع، أي أنه في حالة الأعداد الصحيحة هو العدد 0، وفي حالة السلاسل النصية هو السلسلة الفارغة ""، وأخيرًا في حالة المؤشرات هو القيمة <code>nil</code> إشارةً إلى الحالة الافتراضية لقيمة أي مؤشر.
</p>

<p>
	سنُعدّل في البرنامج التالي على البرنامج السابق، بحيث نعرّف مؤشرًا متغيرًا <code>creature</code> من النوع <code>Creature</code>، لكن دون استنساخ للنسخة الحقيقية من <code>Creature</code> ودون إسناد عنوانها إلى المؤشر؛ أي أن قيمة المؤشر هي <code>nil</code>، ولن نستطيع الرجوع إلى أي من الحقول أو التوابع المُعرّفة في النوع <code>Creature</code>. لنرى ماذا سيحدث:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_30" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    changeCreature</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"3) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func changeCreature</span><span class="pun">(</span><span class="pln">creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    creature</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode">1) &lt;nil&gt;
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x109ac86]

goroutine 1 [running]:
main.changeCreature(0x0)
        /Users/corylanou/projects/learn/src/github.com/gopherguides/learn/_training/digital-ocean/pointers/src/nil.go:18 +0x26
    main.main()
            /Users/corylanou/projects/learn/src/github.com/gopherguides/learn/_training/digital-ocean/pointers/src/nil.go:13 +0x98
        exit status 2
</pre>

<p>
	نلاحظ عند تشغيل البرنامج أن تعليمة الطباعة الأولى 1 نجحت وطبعت قيمة المتغير <code>creature</code> وهي <code>&lt;nil&gt;</code>، لكن عندما وصلنا إلى استدعاء الدالة <code>changeCreature</code> ومحاولة ضبط قيمة الحقل <code>Species</code>، ظهرت <span ipsnoautolink="true">حالة هلع</span> في البرنامج نظرًا لعدم إنشاء نسخة من هذا المتغيّر، وأدى هذا إلى محاولة الوصول إلى موقع ذاكري غير موجود أصلًا أو غير مُحدد.
</p>

<p>
	هذا الأمر شائع في لغة جو، لذلك عندما تتلقى وسيطًا مثل مؤشر، لا بُد من فحصه إذا كان فارغًا أم لا قبل إجراء أي عمليات عليه، لتجنب حالات هلع كهذه.
</p>

<p>
	نتحقق عادةً من قيمة المؤشر في أي دالة تستقبل مؤشرًا مثل وسيط لها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_32" style=""><span class="kwd">if</span><span class="pln"> someVariable </span><span class="pun">==</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هنا يمكن أن نطبع أي رسالة تُشير إلى هذه الحالة أو أن نخرج من الدالة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكنك بذلك التحقق مما إذا كان الوسيط يحمل قيمةً صفريةً أم لا. عند تمرير قيمة صفرية (هنا نقصد <code>nil</code>) قد ترغب في الخروج من الدالة باستخدام تعليمة <code>return</code> أو إعادة رسالة خطأ تخبر المستخدم أن الوسيط الممرّر إلى الدالة أو التابع غير صالح.
</p>

<p>
	تتحقق الشيفرة التالية من وجود قيمة صفرية للمؤشر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_34" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    changeCreature</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"3) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func changeCreature</span><span class="pun">(</span><span class="pln">creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> creature </span><span class="pun">==</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature is nil"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    creature</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضفنا إلى الدالة <code>changeCreature</code> تعليمات لفحص قيمة الوسيط <code>creature</code> فيما إذا كانت صفرية أم لا؛ ففي حال كانت صفرية نطبع "creature is nil" ونخرج من الدالة من خلال تعليمة <code>return</code>، وإلا نتابع العمل في الدالة ونُعدّل قيمة الحقل <code>Species</code>. سنحصل الآن على المخرجات التالية:
</p>

<pre class="ipsCode">1) &lt;nil&gt;
creature is nil
3) &lt;nil&gt;
</pre>

<p>
	لاحظ أنه على الرغم من وجود حالة صفرية للمتغير، إلا أنه لم تحدث حالة هلع للبرنامج لأننا عالجناها.
</p>

<p>
	إذا أنشأنا نسخةً من النوع <code>Creature</code> وأُسندت للمتغير <code>creature</code>، سيتغير الخرج بالتأكيد، لأنه أصبح يُشير إلى موقع ذاكري حقيقي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_36" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pln">
    creature </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Creature</span><span class="pun">{</span><span class="typ">Species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    changeCreature</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"3) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func changeCreature</span><span class="pun">(</span><span class="pln">creature </span><span class="pun">*</span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> creature </span><span class="pun">==</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"creature is nil"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    creature</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنحصل على الناتج المتوقع التالي:
</p>

<pre class="ipsCode">1) &amp;{Species:shark}
2) &amp;{Species:jellyfish}
3) &amp;{Species:jellyfish}
</pre>

<p>
	عندما تتعامل مع المؤشرات، هناك احتمال أن يتعرّض البرنامج لحالة هلع، لذلك يجب عليك التحقق لمعرفة ما إذا كانت قيمة المؤشر صفرية قبل محاولة الوصول إلى أي من الحقول أو التوابع المعرّفة ضمن نوع البيانات الذي يشير إليه.
</p>

<p>
	دعنا نلقي نظرةً على كيفية استخدام المؤشرات مع التوابع.
</p>

<h2>
	مستقبلات مؤشرات التوابع
</h2>

<p>
	المُستقبل receiver في لغة جو هو الوسيط الذي يُعرّف عند التصريح عن التابع. ألقِ نظرةً على الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_38" style=""><span class="pln">type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">c </span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="typ">String</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> c</span><span class="pun">.</span><span class="typ">Species</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	المُستقبل في هذا التابع هو <code>c Creature</code>، وهو يُشير إلى أن نسخة المتغير <code>c</code> من النوع <code>Creature</code> وأنك ستستخدمه ليُشير إلى نسخة متغير من هذا النوع.
</p>

<p>
	يختلف أيضًا سلوك التوابع كما هو الحال في الدوال التي يختلف فيها سلوك الدالة تبعًا لطريقة تمرير الوسيط (بالمرجع أو بالقيمة). ينبع الاختلاف الأساسي من أنه إذا صرّحت عن دالة مع مُستقبل "قيمة"، فلن تتمكن من إجراء تغييرات على نسخة هذا النوع التي عُرّف التابع عليه. عمومًا، ستكون هناك أوقات تحتاج فيها أن يكون تابعك قادرًا على تحديث نسخة المتغير الذي تستخدمه، ولإجراء هكذا تحديثات ينبغي عليك جعل المستقبل "مؤشرًا".
</p>

<p>
	دعنا نضيف التابع <code>Reset</code> للنوع <code>Creature</code>، الذي يسند سلسلةً نصيةً فارغة إلى الحقل <code>Species</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_40" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">c </span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Reset</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    c</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="typ">Creature</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Creature</span><span class="pun">{</span><span class="typ">Species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    creature</span><span class="pun">.</span><span class="typ">Reset</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا شغّلت البرنامج ستحصل على الخرج:
</p>

<pre class="ipsCode">1) {Species:shark}
2) {Species:shark}
</pre>

<p>
	لاحظ أنه على الرغم من ضبطنا قيمة الحقل <code>Species</code> على السلسلة الفارغة في التابع <code>Reset</code>، إلا أننا عندما طبعنا المتغير <code>creature</code> في الدالة <code>main</code> حصلنا على "shark". السبب في عدم انتقال التغيير هو استخدامنا مُستقبل قيمة في تعريف التابع <code>Reset</code>، وبالتالي سيكون لهذا التابع إمكانية التعديل فقط على نسخة المتغير <code>creature</code> وليس المتغير الأصلي. بالتالي، إذا أردنا تحديث هذه القيمة؛ أي التعديل على النسخة الأصلية للمتغير، فيجب علينا تعريف مُستقبل مؤشر.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3334_42" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

type </span><span class="typ">Creature</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Species</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">c </span><span class="pun">*</span><span class="typ">Creature</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Reset</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    c</span><span class="pun">.</span><span class="typ">Species</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var creature </span><span class="typ">Creature</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Creature</span><span class="pun">{</span><span class="typ">Species</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"1) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
    creature</span><span class="pun">.</span><span class="typ">Reset</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"2) %+v\n"</span><span class="pun">,</span><span class="pln"> creature</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أننا أضفنا المعامل "*" أمام النوع <code>Creature</code> عندما صرّحنا عن التابع <code>Reset</code>، وهذا يعني أن الوسيط الذي نُمرره أصبح مؤشرًا، وبالتالي أصبحت كل التعديلات التي نُجريها من خلاله مُطبّقةً على المتغير الأصلي.
</p>

<pre class="ipsCode">1) {Species:shark}
2) {Species:}
</pre>

<p>
	لاحظ أن التابع <code>Reset</code> عدّل قيمة الحقل <code>Species</code> كما توقعنا، وهذا مُماثل لفكرة التمرير بالمرجع أو القيمة في الدوال.
</p>

<h2>
	خاتمة
</h2>

<p>
	تؤثر طريقة تمرير الوسطاء (بالمرجع أو القيمة) إلى التوابع أو الدوال على آلية الوصول إلى المتغير المُمرّر؛ ففي حالة التمرير بالمرجع يكون التعديل مباشرةً على المتغير الأصلي، أما في الحالة الثانية فيكون على نسخة من المتغير. الآن بعد أن تعرفت على المؤشرات، أصبح بإمكانك التعرف على استخدامها مع الواجهات أيضًا.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/conceptual_articles/understanding-pointers-in-go" rel="external nofollow">Understanding Pointers in Go</a> لصاحبه Gopher Guides.
</p>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%B3%D9%88%D9%85-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D9%84%D8%AA%D8%AE%D8%B5%D9%8A%D8%B5-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%86%D9%81%D9%8A%D8%B0%D9%8A%D8%A9-binaries-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1970/" rel="">استخدام وسوم البناء لتخصيص الملفات التنفيذية Binaries في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%85%D8%A4%D8%B4%D8%B1%D8%A7%D8%AA-pointers-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-c-r1679/" rel="">المؤشرات Pointers في لغة سي C</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/cpp/%D8%A7%D9%84%D9%85%D8%A4%D8%B4%D8%B1%D8%A7%D8%AA-pointers-%D9%81%D9%8A-cpp-r912/" rel="">المؤشرات Pointers في لغة Cpp</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1975</guid><pubDate>Sat, 13 May 2023 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x648;&#x633;&#x648;&#x645; &#x627;&#x644;&#x628;&#x646;&#x627;&#x621; &#x644;&#x62A;&#x62E;&#x635;&#x64A;&#x635; &#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x646;&#x641;&#x64A;&#x630;&#x64A;&#x629; Binaries &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%B3%D9%88%D9%85-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D9%84%D8%AA%D8%AE%D8%B5%D9%8A%D8%B5-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%86%D9%81%D9%8A%D8%B0%D9%8A%D8%A9-binaries-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1970/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_05/--------Go.png.bf0f65bd08c837e6f3cdceb1a674b8e7.png" /></p>
<p>
	وسم البناء Build tag أو قيد البناء Build constraint هو مُعرّف يُضاف إلى التعليمات البرمجية لتحديد متى يجب تضمين ملف ما في حزمة أثناء عملية البناء <code>build</code>، ويتيح لك إمكانية بناء إصدارات مُختلفة لتطبيقك من نفس التعليمات البرمجية المصدرية والتبديل بينها بطريقة سريعة ومنظمة.
</p>

<p>
	يستخدم العديد من المطورين وسوم البناء لتحسين سير العمل Workflow عند بناء تطبيقات متوافقة مع جميع أنظمة تشغيل الأساسية Cross-platform، مثل البرامج التي تتطلب تغييرات في التعليمات البرمجية لمراعاة الفروقات بين أنظمة التشغيل المختلفة. تُستخدم وسوم البناء أيضًا من أجل <a href="https://en.wikipedia.org/wiki/Integration_testing" rel="external nofollow">اختبار التكامل Integration testing</a>، مما يسمح لك بالتبديل بسرعة بين الشيفرة المتكاملة والشيفرة باستخدام <a href="https://en.wikipedia.org/wiki/Mock_object" rel="external nofollow">خادم زائف Mock server أو شيفرة اختبارية بديلة Stub</a>، وبين المستويات المختلفة لمجموعات الميزات التي يتضمنها تطبيقك.
</p>

<p>
	لنأخذ مثلًا، مشكلة اختلاف مجموعات الميزات التي تُمنح للعملاء، فعند كتابة بعض التطبيقات، قد ترغب في التحكم بالمميزات التي يجب تضمينها في الثنائي binary، مثل التطبيق الذي يوفّر مستويات مجانية واحترافية Pro ومتقدمة Enterprise. كلما رفع العميل من مستوى اشتراكه في هذه التطبيقات، توفّرت له المزيد من الميزات وأصبحت غير مقفلة.
</p>

<p>
	يمكنك حل هذه المشكلة من خلال الاحتفاظ بمشاريع منفصلة ومحاولة إبقائها متزامنةً مع بعضها بعضًا من خلال استخدام <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/" rel="">تعليمات الاستيراد import</a>، وعلى الرغم من أن هذا النهج سيعمل، لكنه سيصبح مملًا بمرور الوقت وعرضةً للخطأ، وقد يكون النهج البديل هو استخدام وسوم البناء.
</p>

<p>
	ستستخدم في هذه المقالة وسوم البناء في لغة جو، لإنشاء ملفات تنفيذية مختلفة تُقدم مجموعات ميزات مجانية واحترافية ومتقدمة لتطبيقك. سيكون لكل من هذه الملفات التنفيذية مجموعةٌ مختلفةٌ من الميزات المتاحة، إضافةً للإصدار المجاني، الذي هو الخيار الافتراضي.
</p>

<p>
	<strong>ملاحظات:</strong>
</p>

<ul>
	<li>
		<p>
			التوافق مع أنظمة التشغيل الأساسية Cross-platform: ‏ هو مصطلح يستخدم في <a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">علم الحوسبة</a> يشير إلى برامج الحاسوب أو أنظمة التشغيل أو لغات الحاسوب أو <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> وتطبيقاتها التي يمكنها العمل على عدة منصات حاسوبية. هناك نوعان رئيسيان من البرمجيات المتوافقة مع أنظمة التشغيل الأساسية، إذ يستلزم الأول بناءه لكل منصة يمكنه العمل عليها، والثاني يمكنه العمل مباشرةً على أي منصة تدعمه.
		</p>
	</li>
	<li>
		<p>
			اختبار التكامل Integration testing: يمثّل مرحلة اختبار البرامج التي تتكامل فيها الوحدات البرمجية وتُختبر مثل وحدة واحدة متكاملة. يُجرى اختبار التكامل لتقييم مدى امتثال نظام أو مكون برمجي لمتطلبات وظيفية محددة، وغالبًا ما تكون هذه المتطلبات مدونة في توثيق الخاصيات والمتطلبات.
		</p>
	</li>
	<li>
		<p>
			خادم زائف Mock server: هو إطار عمل يهدف إلى تبسيط اختبار التكامل. تعتمد هذه الأُطر على مفهوم الكائنات الزائفة، وهي كائنات محاكاة تحاكي سلوك الكائنات الحقيقية بطرق خاضعة للرقابة، وتكون غالبًا بمثابة جزء من عملية اختبار البرنامج. يُنشئ المبرمج عادةً كائنًا زائفًا لاختبار سلوك بعض الأشياء الأخرى، بنفس الطريقة التي يستخدم بها مصمم السيارة دمية اختبار التصادم لمحاكاة السلوك الديناميكي للإنسان في اصطدام السيارة. هذه التقنية قابلة للتطبيق أيضًا في البرمجة العامة.
		</p>
	</li>
	<li>
		<p>
			شيفرة اختبارية بديلة Stub: برنامج صغير يُستبدل ببرنامج أطول، ربما يُحمّل لاحقًا، أو يكون موجودًا عن بُعد في مكان ما، إذ يكون بديلًا مؤقتًا للشيفرة التي لم تُطوّر بعد، وهذه الشيفرة مفيدة جدًا في نقل البيانات والحوسبة الموزعة وكذلك تطوير البرمجيات واختبارها عمومًا.
		</p>
	</li>
</ul>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	أن يكون لديك مساحة عمل خاصة في لغة جو، وإذا لم يكن لديك مساحة عمل، اتبع سلسلة المقالات التالية: <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-r1766/" rel="">تثبيت لغة جو Go وإعداد بيئة برمجة محلية على أبونتو Ubuntu</a>، و<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%85%D8%A7%D9%83-macos-r1767/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على نظام ماك macOS</a>، و<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-r1768/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على ويندوز</a>.
</p>

<h2>
	بناء النسخة المجانية
</h2>

<p>
	سنبدأ ببناء الإصدار المجاني من التطبيق، إذ سيكون هو الإصدار الافتراضي عند تنفيذ الأمر <code>go build</code> دون أي وسوم بناء. سنستخدم لاحقًا وسوم البناء لإضافة أجزاء أخرى إلى برنامجنا.
</p>

<p>
	أنشئ مجلدًا باسم التطبيق الخاص بك في مجلد src، وسنستخدم هنا الاسم "app":
</p>

<pre class="ipsCode">$ mkdir app
</pre>

<p>
	انتقل إلى المجلد "app" الذي أنشأته:
</p>

<pre class="ipsCode">$ cd app
</pre>

<p>
	أنشئ الآن ملف "main.go" داخل مجلد المشروع. استخدمنا هنا محرر النصوص نانو nano لفتح وإنشاء الملف:
</p>

<pre class="ipsCode">$ nano main.go
</pre>

<p>
	سنعرّف الآن الإصدار المجاني من التطبيق. انسخ المحتويات التالية إلى ملف main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_8" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var features </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="pln">
  </span><span class="str">"Free Feature #1"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"Free Feature #2"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> f </span><span class="pun">:=</span><span class="pln"> range features </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"&gt;"</span><span class="pun">,</span><span class="pln"> f</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أنشأنا برنامجًا يُصرّح عن <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D8%AC%D9%88-go-r1866/" rel="">شريحة Slice</a> باسم <code>features</code>، تحتوي على سلسلتين نصيتين strings تمثلان ميزات إصدار تطبيقنا المجاني. تستخدم الدالة <code>()main</code> حلقة <code>for</code> لتنتقل عبر عناصر شريحة الميزات من أجل طباعة جميع الميزات المتاحة على الشاشة.
</p>

<p>
	احفظ الملف واخرج منه، وبعد حفظ الملف لن نضطر إلى تحريره مرةً أخرى خلال هذا المقال، إذ سنستخدم وسوم البناء لتغيير ميزات الثنائيات التي سنبنيها منها.
</p>

<p>
	اِبنِ وشغّل البرنامج:
</p>

<pre class="ipsCode">$ go build
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
</pre>

<p>
	طبع البرنامج ميزتين مجانيتين تكملان ميزات الإصدار المجاني من تطبيقنا.
</p>

<p>
	أكملنا الآن الإصدار المجاني المُتمثّل بتطبيق يحتوي على مجموعة ميزات أساسية جدًا. سنبني بعد ذلك شيفرة تمكننا من إضافة مزيدٍ من الميزات إلى التطبيق عند البناء.
</p>

<h2>
	إضافة ميزات احترافية باستخدام go build
</h2>

<p>
	تجنّبنا حتى الآن إجراء تغييرات على الملف main.go، وذلك لمحاكاة بيئة إنتاج عامة ينبغي فيها إضافة الشيفرة دون تغيير الشيفرة الرئيسية أو كسرها.
</p>

<p>
	ونظرًا لإمكانية تعديل ملف main.go، سنحتاج إلى استخدام آلية أخرى لإدخال المزيد من الميزات إلى شريحة <code>features</code> باستخدام وسوم البناء.
</p>

<p>
	سننشئ ملفًا جديدًا باسم "pro.go"، والذي سيستخدم الدالة <code>()init</code> لإضافة المزيد من الميزات إلى شريحة <code>features</code>:
</p>

<pre class="ipsCode">$ nano pro.go
</pre>

<p>
	أضف المحتويات التالية إلى الملف بعد فتحه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_10" style=""><span class="pln">package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Pro Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Pro Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدمنا الدالة <code>()init</code> لتشغيل الشيفرة قبل الدالة <code>()main</code> في التطبيق، ثم استخدمنا الدالة <code>()append</code> لإضافة ميزات احترافية إلى شريحة <code>features</code>.
</p>

<p>
	احفظ الملف واخرج منه، ثم صرّف التطبيق وشغّله باستخدام الأمر التالي:
</p>

<pre class="ipsCode">$ go build
</pre>

<p>
	نظرًا لوجود ملفين الآن في المجلد الحالي، هما "pro.go" و "main.go"، سينشئ الأمر <code>go build</code> ملفًا ثنائيًا من كليهما:
</p>

<pre class="ipsCode">$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
&gt; Pro Feature #1
&gt; Pro Feature #2
</pre>

<p>
	يتضمن التطبيق الآن كلًا من الميزات الاحترافية والمجانية، وهذا غير مرغوب بالوضع الحالي للتطبيق؛ فلا يوجد تمييز بين الإصدارات، إذ يتضمن الإصدار المجاني الميزات التي من المفترض أن تكون متوفرة فقط في الإصدار الاحترافي. يمكنك حل المشكلة عن طريق إضافة المزيد من التعليمات البرمجية لإدارة المستويات المختلفة للتطبيق، أو استخدام وسوم البناء لإخبار أدوات جو عن الملفات التي تكون بامتداد "go."،التي يجب بناؤها وتلك التي يجب تجاهلها. سنضيف في الخطوة التالية وسوم البناء.
</p>

<h2>
	إضافة وسوم البناء
</h2>

<p>
	يمكنك الآن استخدام وسوم البناء لتمييز الإصدار الاحترافي عن المجاني. يكون شكل الوسم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_14" style=""><span class="com">// +build tag_name</span></pre>

<p>
	من خلال وضع هذا السطر البرمجي في بداية الحزمة الخاصة بك (في أول سطر) وتبديل <code>tag_name</code> إلى اسم وسم البناء الذي تريده، ستُوسّم هذه الحزمة لتصبح شيفرةً يمكن تضمينها اختياريًّا في الثنائي النهائي. دعنا نرى هذا عمليًا عن طريق إضافة وسم البناء إلى ملف pro.go لإخبار الأمر <code>go build</code> بتجاهلها ما لم يُحدّد الوسم. افتح الملف في محرر النصوص الخاص بك:
</p>

<pre class="ipsCode">$ nano pro.go
</pre>

<p>
	ضِف مايلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_12" style=""><span class="com">// +build pro</span><span class="pln">

package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Pro Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Pro Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضفنا في بداية الملف pro.go السطر <code>‎// +build pro</code>متبوعًا بسطر جديد فارغ؛ وهذا السطر الجديد ضروري، وبدونه سيفسّر جو السطر السابق على أنه تعليق. يجب أن تكون تصريحات وسوم البناء أيضًا في أعلى الملف ذي الامتداد "go." دومًا، لا تضع أي شيء، ولا حتى التعليقات قبلها.
</p>

<p>
	يُخبِر التصريح <code>build+</code> الأمر <code>go build</code> أن هذا ليس تعليقًا، بل هو وسم بناء. الجزء الثاني هو الوسم <code>pro</code>، فبإضافة هذا الوسم في الجزء العلوي من ملف pro.go، سيُضمّن الأمر <code>go build</code> ملف pro.go في حال وجود الوسم <code>pro</code> فقط. صرّف التطبيق الآن وشغّله:
</p>

<pre class="ipsCode">$ go build
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
</pre>

<p>
	بما أن ملف pro.go يتطلب وجود الوسم <code>pro</code>، سيجري تجاهل الملف وسيُصرّف التطبيق دونه.
</p>

<p>
	عند استخدام الأمر <code>go build</code>، يمكننا استخدام الراية <code>tags-</code> لتضمين شيفرة محددة لكي تُصرّف مع التطبيق عن طريق إضافة وسم الشيفرة مثل وسيط. سنجرّب ذلك مع الوسم <code>pro</code>:
</p>

<pre class="ipsCode">$ go build -tags pro
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
&gt; Pro Feature #1
&gt; Pro Feature #2
</pre>

<p>
	سنحصل الآن على الميزات الاحترافية فقط إذا أضفنا الوسم <code>pro</code>.
</p>

<p>
	هذا جيد إذا كان هناك إصدارين فقط، ولكن الأمور تصبح معقدةً عند وجود مزيدٍ من الإصدارات وإضافة مزيدٍ من الوسوم. سنستخدم في الخطوة التالية وسوم بناء متعددة مع <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-boolean-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1847/" rel="">منطق بولياني Boolean logic</a>، لإضافة إصدار مُتقدم.
</p>

<h2>
	استخدام المنطق البولياني مع وسوم البناء
</h2>

<p>
	عندما تكون هناك وسوم بناء متعددة في حزمة جو، تتفاعل الوسوم مع بعضها بعضًا باستخدام المنطق البولياني. لتوضيح ذلك، سنضيف المستوى "مُتقدم Enterprise" لتطبيقنا باستخدام الوسم <code>pro</code> والوسم <code>enterprise</code>.
</p>

<p>
	سنحتاج من أجل بناء ثنائي للإصدار المتقدم إلى تضمين كل من الميزات الافتراضية والميزات الاحترافية، ومجموعة جديدة من الميزات الخاصة بالإصدار المتقدم. افتح محررًا وأنشئ ملفًا جديدًا enterprise.go، لنضع فيه الميزات الجديدة:
</p>

<pre class="ipsCode">$ nano enterprise.go
</pre>

<p>
	ستبدو محتويات enterprise.go متطابقة تقريبًا مع pro.go ولكنها ستحتوي على ميزات جديدة. ضِف الأسطر التالية إلى الملف "enterprise.go":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_16" style=""><span class="pln">package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الملف واخرج.
</p>

<p>
	لا يحتوي ملف enterprise.go حاليًا على أي وسوم بناء، وكما تعلّمت عندما أضفت pro.go، فهذا يعني أن هذه الميزات ستضاف إلى الإصدار المجاني عند تنفيذ <code>go.build</code>. بالنسبة إلى pro.go، أضفت <code>build pro+ \\</code> متبوعًا بسطر فارغ في أعلى الملف لإخبار الأمر <code>go build</code> أنه يجب تضمينه فقط عند استخدام <code>tags pro-</code>. تحتاج في هذه الحالة فقط إلى وسم بناء واحد لتحقيق الهدف، لكن عند إضافة الميزات الجديدة المتقدمة، إذ يجب أن يكون لديك أولًا ميزات احترافية Pro.
</p>

<p>
	سنجعل الآن ملف enterprise.go يدعم وسم البناء pro. افتح الملف باستخدام محرر النصوص الخاص بك:
</p>

<pre class="ipsCode">$ nano enterprise.go
</pre>

<p>
	ضِف بعد ذلك وسم البناء قبل سطر التصريح <code>package main</code> وتأكد من إضافة سطر فارغ كما تحدثنا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_18" style=""><span class="com">// +build pro</span><span class="pln">

package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الملف واغلقه، ثم صرّف التطبيق دون إضافة أي وسوم (الإصدار المجاني):
</p>

<pre class="ipsCode">$ go build
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
</pre>

<p>
	لاحظ أن الميزات المتقدمة لا تظهر في الإصدار المجاني. دعنا الآن نضيف وسم الإصدار المحترف <code>pro</code> ونبني التطبيق ونشغّله مرةً أخرى:
</p>

<pre class="ipsCode">$ go build -tags pro
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
&gt; Enterprise Feature #1
&gt; Enterprise Feature #2
&gt; Pro Feature #1
&gt; Pro Feature #2
</pre>

<p>
	ليس هذا فعلًا ما نحتاجه حتى الآن، لأن الميزات المتقدمة تظهر عندما نبني إصدار احترافي، وسنحتاج إلى استخدام وسم بناء آخر لحل هذه المشكلة. بالنسبة للوسم <code>enterprise</code> فهو على عكس الوسم <code>pro</code>، إذ نحتاج هنا إلى التأكد من توفُّر الميزات الاحترافية <code>pro</code> والمتقدمة <code>enterprise</code> في نفس الوقت.
</p>

<p>
	يراعي نظام البناء في جو هذا الموقف من خلال السماح باستخدام بعض المنطق البولياني في نظام وسوم البناء.
</p>

<p>
	لنفتح enterprise.go مرةً أخرى:
</p>

<pre class="ipsCode">$ nano enterprise.go
</pre>

<p>
	سنضيف الآن وسمًا إلى هذا الملف باسم <code>enterprise</code> كما فعلنا سابقًا عند إضافة الوسم <code>pro</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_20" style=""><span class="com">// +build pro enterprise</span><span class="pln">

package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الملف واخرج، ثم صرّف التطبيق مع إضافة الوسم <code>enterprise</code>:
</p>

<pre class="ipsCode">$ go build -tags enterprise
$ ./app
</pre>

<p>
	سيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
&gt; Enterprise Feature #1
&gt; Enterprise Feature #2
</pre>

<p>
	لاحظ أننا خسرنا ميزات الإصدار الاحترافي، وسبب ذلك هو أنه عندما نضع عدة وسوم بناء ضمن نفس السطر في ملف "go."، سيفسر <code>go build</code> أن العلاقة بينهما هي OR المنطقية. إذًا، بإضافة السطر <code>build pro enterprise+ \\</code> سيُبنى الملف enterprise.go في حال وجود إحدى الوسمين <code>pro</code> أو <code>enterprise</code>.
</p>

<p>
	نحن الآن بحاجة إلى كتابة وسوم البناء بطريقة صحيحة مع استخدام المنطق AND، ولفعل ذلك سنكتب كلًا من الوسمين في سطر منفصل، وبهذا الشكل سيفسّر <code>go build</code> على أن العلاقة بينهما AND. افتح الملف enterprise.go مرةً أخرى وافصل وسوم البناء في أسطر منفصلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3878_22" style=""><span class="com">// +build pro</span><span class="pln">
</span><span class="com">// +build enterprise</span><span class="pln">

package main

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  features </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">features</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"Enterprise Feature #2"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن، صرّف تطبيقك مع الوسم <code>enterprise</code>:
</p>

<pre class="ipsCode">$ go build -tags enterprise
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
</pre>

<p>
	ما زال هذا غير كافي لأن <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%B9%D8%A7%D9%85%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r778/" rel="">منطق AND</a> يتطلب أن يكون العنصران محققين "true"؛ إذًا نحتاج إلى وجود وسمي البناء <code>pro</code> و <code>enterprise</code>:
</p>

<pre class="ipsCode">$ go build -tags "enterprise pro"
$ ./app
</pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">&gt; Free Feature #1
&gt; Free Feature #2
&gt; Enterprise Feature #1
&gt; Enterprise Feature #2
&gt; Pro Feature #1
&gt; Pro Feature #2
</pre>

<p>
	يمكنك الآن بناء التطبيق من نفس شجرة المصدر بعدة طرق مختلفة وفقًا للميزات التي تريد توفيرها.
</p>

<p>
	استخدمنا في هذا المثال وسم بناء جديد باستخدام وسم <code>build+ //</code> للدلالة على منطق AND، ولكن هناك طرق بديلة لتمثيل المنطق البولياني باستخدام وسوم البناء. يحتوي الجدول التالي على بعض الأمثلة على التنسيقات النحوية الأخرى لوسوم البناء، جنبًا إلى جنب مع مكافئها المنطقي:
</p>

<table>
	<thead>
		<tr>
			<th>
				قاعدة وسم البناء
			</th>
			<th>
				عينة عن الوسم
			</th>
			<th>
				التعليمة المنطقية
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				عناصر مفصولة بفراغ
			</td>
			<td>
				<code>build pro enterprise+ \\</code>
			</td>
			<td>
				محترف أو متقدم <code>pro</code> OR <code>enterprise</code>
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				عناصر مفصولة بفاصلة
			</td>
			<td>
				<code>build pro,enterprise+ \\</code>
			</td>
			<td>
				محترف ومتقدم <code>pro</code> AND <code>enterprise</code>
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				عناصر مفصولة بعلامة تعجب
			</td>
			<td>
				<code>build !pro+ \\</code>
			</td>
			<td>
				ليس محترف NOT pro
			</td>
		</tr>
	</tbody>
</table>

<h2>
	خاتمة
</h2>

<p>
	تعرّفت في هذا المقال على كيفية استخدام وسوم البناء للتحكم في الملفات التي ستُصرّف إلى ملفات ثنائية في جو؛ إذ صرّحنا أولًا عن وسم البناء، ثم استخدمناها في <code>go build</code> ثم دمجنا عدة وسوم باستخدام المنطق البولياني. أخيرًا بنينا برنامجًا يتضمن مجموعات ميزات مختلفة كل منها يمثل إصدارًا (مجاني، احترافي، متقدم)، والذي أظهر قوة وسوم البناء التي تمثّل أداةً قوية جدًا بالتحكم بإصدارات المشروع.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags" rel="external nofollow">Customizing Go Binaries with Build Tags</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%AF%D8%A7%D9%84%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-init-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1964/" rel="">تعرف على دالة التهيئة init واستخدامها في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1846/" rel="">العمليات الحسابية في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1970</guid><pubDate>Thu, 04 May 2023 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x62F;&#x627;&#x644;&#x629; &#x627;&#x644;&#x62A;&#x647;&#x64A;&#x626;&#x629; init &#x648;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645;&#x647;&#x627; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%AF%D8%A7%D9%84%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-init-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1964/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/-init----Go.png.bc7ee9c4ce72911514ffd2991c0d9398.png" /></p>
<p>
	تُستخدَم الدالة المُعرّفة مسبقًا <code>()init</code> في لغة جو لجعل شيفرة مُحدَّدة تُنفّذ قبل أيّ شيفرة أخرى ضمن الحزمة الخاصة بك، إذ ستُنفَّذ هذه الشيفرة عند استيراد الحزمة مباشرةً، وبالتالي يمكنك استخدام هذه الدالة عندما تحتاج إلى تهيئة تطبيقك في حالة معينة مثل أن يكون لديك إعدادات أوليّة محددة أو مجموعة من الموارد التي يحتاجها تطبيقك لكي يبدأ.
</p>

<p>
	تُستخدم أيضًا عند استيراد <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%AC%D8%A7%D9%86%D8%A8%D9%8A%D9%91%D9%8E%D8%A9-side-effects-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%D8%9F-r549/" rel="">تأثير جانبي side effect</a>، وهي تقنية تستخدَم لضبط حالة البرنامج من خلال استيراد حزمة معينة، ويُستخدَم هذا غالبًا لتسجيل <code>register</code> حزمة مع أخرى للتأكد من عمل البرنامج بطريقة صحيحة.
</p>

<p>
	يُعَدّ استخدام الدالة <code>()init</code> مفيدًا، ولكنه يجعل من قراءة الشيفرة أمرًا صعبًا في بعض الأحيان وذلك لأنّ نسخة <code>()init</code> التي يصعُب العثور عليها ستؤثر إلى حد كبير في ترتيب تنفيذ شفرات البرنامج، وبالتالي لا بدّ من فهم هذه الدالة جيدًا لاستخدامها بطريقة صحيحة.
</p>

<p>
	سنتعلم في هذا المقال استخدام الدالة <code>()init</code> لإعداد وتهيئة متغيرات حزمة معيّنة وعمليات حسابية تجرى لمرة واحدة وتسجيل حزمة لاستخدامها مع حزمة أخرى.
</p>

<h2>
	المتطلبات
</h2>

<p>
	ستحتاج من أجل بعض الأمثلة في هذا المقال إلى مساحة عمل خاصة مُهيئة وجاهزة، فإذا لم يكن لديك واحدة، فيمكنك اتباع المقالات السابقة حيث تحدثنا عن <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-r1768/" rel="">كيفية إعداد وتثبيت بيئة برمجة محلية في لغة جو</a>. إذ يستخدِم هذا المقال بنية الملفات التالية:
</p>

<pre class="ipsCode">.
├── bin 
│ 
└── src
    └── github.com
        └── gopherguides
</pre>

<h2>
	التصريح عن الدالة ()init
</h2>

<p>
	بمجرّد التصريح عن أيّ دالة <code>()init</code> سيُنفّذها مصرِّف جو قبل أيّ شيفرة أخرى في الحزمة، وسنوضِّح في هذا القسم كيفية تعريف هذه الدالة وكيف تؤثر على تشغيل الحزمة، لذا دعونا الآن نلقي نظرةً على مثال لا يتضمن هذه الدالة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_9" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var weekday string

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Today is %s"</span><span class="pun">,</span><span class="pln"> weekday</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	صرّحنا في هذا البرنامج عن متغير عام <code>weekday</code> من النوع <code>string</code>، وبما أننا لم نُهيّئ هذا المتغير بأيّ قيمة، فستكون القيمة الافتراضية لها هي السلسلة الفارغة، وبالتالي لن نرى أيّ شيء عند طباعتها، ولنشغّل هذه الشيفرة كما يلي:
</p>

<pre class="ipsCode">$ go run main.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Today is
</pre>

<p>
	يمكننا إعطاء قيمة أوليّة إلى المتغير <code>weekday</code> من خلال الدالة <code>()init</code> بحيث نُهيّئها بقيمة اليوم الحالي، لذا سنعدِّل على الشيفرة السابقة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_11" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

var weekday string

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    weekday </span><span class="pun">=</span><span class="pln"> time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">Weekday</span><span class="pun">().</span><span class="typ">String</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Today is %s"</span><span class="pun">,</span><span class="pln"> weekday</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدمنا في هذه الشيفرة الحزمة <code>time</code> للحصول على اليوم الحالي من خلال كتابة <code>()Now().Weekday().String</code> ثم استخدمنا الدالة <code>()init</code> لتهيئة المتغير <code>weekday</code> بها، والآن إذا شغّلنا البرنامج، فسنحصل على خرج مُختلف عن المرة السابقة:
</p>

<pre class="ipsCode">Today is Monday
</pre>

<p>
	كان الهدف من هذا المثال هو توضيح عمل الدالة، إلا أن استخدامها الأكثر شيوعًا يكون عند استيراد حزمة، فقد نكون بحاجة إلى إتمام بعض عمليات التهيئة أو بعض العمليات الأولية قبل استخدام الحزمة، لذا دعنا ننشئ برنامجًا سيتطلب تهيئة محددة للحزمة لتعمل على النحو المنشود.
</p>

<h2>
	تهيئة الحزم عند استيرادها
</h2>

<p>
	بدايةً، سنكتب برنامجًا بسيطًا يختار عشوائيًا عنصرًا من شريحة ما ويطبعها، ولن نستخدِم هنا الدالة <code>()init</code> لكي نُبيّن المشكلة التي ستحدث وكيف ستحلّها هذه الدالة فيما بعد، لذا أنشئ مجلدًا اسمه creature من داخل المجلد /src/github.com/gopherguides كما يلي:
</p>

<pre class="ipsCode">$ mkdir creature
</pre>

<p>
	أنشئ بداخله الملف creature.go:
</p>

<pre class="ipsCode">$ nano creature/creature.go
</pre>

<p>
	ضع بداخل الملف التعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_13" style=""><span class="pln">package creature

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"math/rand"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

var creatures </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"octopus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dolphin"</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Random</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    i </span><span class="pun">:=</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">creatures</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> creatures</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُعرِّف هذا الملف متغيرًا يسمى <code>creatures</code> يحتوي على مجموعة من أسماء الكائنات البحرية على أساس قيم لهذه الشريحة، كما يحتوي هذا الملف على دالة عشوائية مُصدّرة تُعيد قيمةً عشوائيةً من هذه الشريحة. احفظ الملف واخرج منه.
</p>

<p>
	سننشئ الآن الحزمة <code>cmd</code> التي سنستخدِمها لكتابة الدالة <code>()main</code> واستدعاء الحزمة <code>creature</code>، ولأجل ذلك يجب أن نُنشئ مجلدًا اسمه cmd بجانب المجلد creature كما يلي:
</p>

<pre class="ipsCode">$ mkdir cmd
</pre>

<p>
	سنُنشئ بداخله الملف main.go:
</p>

<pre class="ipsCode">$ nano cmd/main.go
</pre>

<p>
	أضف المحتويات التالية إلى المجلد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_15" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/creature"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">.</span><span class="typ">Random</span><span class="pun">())</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">.</span><span class="typ">Random</span><span class="pun">())</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">.</span><span class="typ">Random</span><span class="pun">())</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">creature</span><span class="pun">.</span><span class="typ">Random</span><span class="pun">())</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استوردنا هنا الحزمة <code>creature</code>، ثم استدعينا الدالة <code>()creature.Random</code> بداخل الدالة <code>()main</code> للحصول على عنصر عشوائي من الشريحة وطباعته أربع مرات. احفظ الملف main.go ثم أغلقه.
</p>

<p>
	انتهينا الآن من كتابة الشيفرة، لكن قبل أن نتمكن من تشغيل هذا البرنامج، سنحتاج أيضًا إلى إنشاء ملفَين من ملفات الضبط configuration حتى تعمل التعليمات البرمجية بطريقة صحيحة.
</p>

<p>
	تُستخدَم وحدات لغة جو Go Modules لضبط اعتماديات الحزمة لاستيراد الموارد، إذ تُعَدّ وحدات لغة جو ملفات ضبط موضوعة في مجلد الحزمة الخاص بك والتي تخبر المُصرِّف بمكان استيراد الحزم منه، ولن نتحدث عن وحدات لغة جو في هذا المقال، لكن سنكتب السطرين التاليين لكي تعمل الشيفرة السابقة، لذا أنشئ الملف go.mod ضمن المجلد cmd كما يلي:
</p>

<pre class="ipsCode">$ nano cmd/go.mod
</pre>

<p>
	ثم ضع بداخله التعليمات التالية:
</p>

<pre class="ipsCode">module github.com/gopherguides/cmd
 replace github.com/gopherguides/creature =&gt; ../creature
</pre>

<p>
	يخبر السطر الأول المصرِّف أنّ الحزمة <code>cmd</code> التي أنشأناها هي في الواقع github.com/gopherguides/cmd؛ أما السطر الثاني، فيُخبر المصرِّف أنه يمكن العثور على المجلد github.com/gopherguides/creature محليًا ضمن المجلد <code>creature/..</code>، لذا احفظ وأغلق الملف ثم أنشئ ملف go.mod في مجلد creature:
</p>

<pre class="ipsCode">$ nano creature/go.mod
</pre>

<p>
	أضف السطر التالي من التعليمات البرمجية إلى الملف:
</p>

<pre class="ipsCode">module github.com/gopherguides/creature
</pre>

<p>
	يخبر هذا المصرِّف أنّ الحزمة <code>creature</code> التي أنشأناها هي في الواقع الحزمة github.com/gopherguides/creature، وبدون ذلك لن تعرف الحزمة <code>cmd</code> مكان استيراد هذه الحزمة. احفظ وأغلق الملف.
</p>

<p>
	يجب أن يكون لديك الآن بنية المجلد التالية:
</p>

<pre class="ipsCode">├── cmd
│   ├── go.mod
│   └── main.go
└── creature
    ├── go.mod
    └── creature.go
</pre>

<p>
	الآن بعد أن انتهينا من إنشاء ملفات الضبط اللازمة أصبح بالإمكان تشغيل البرنامج من خلال الأمر التالي:
</p>

<pre class="ipsCode">$ go run cmd/main.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">jellyfish
squid
squid
dolphin
</pre>

<p>
	حصلنا عند تشغيل هذا البرنامج على أربع قيم وطبعناها، وإذا أعدنا تشغيل هذا البرنامج عدة مرات، فسنلاحظ أننا نحصل دائمًا على الخرج نفسه بدلًا من نتيجة عشوائية كما هو متوقع، وسبب ذلك هو أنّ الحزمة <code>rand</code> تُنشئ أعدادًا شبه عشوائية تولِّد الخرج نفسه باستمرار من أجل حالة أولية initial state واحدة.
</p>

<p>
	للحصول على عشوائية أكبر، يمكننا إعادة ضبط <a href="https://academy.hsoub.com/questions/14600-%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%86%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-nprandomseed0-%D8%9F/" rel="">مفتاح توليد الأعداد seed</a> في الحزمة، أو ضبط مصدر متغير بحيث تختلف الحالة الأولية في كل مرة نُشغّل فيها البرنامج، وفي لغة جو من الشائع استخدام الوقت الحالي على أساس مفتاح توليد في حزمة <code>rand</code>، وبما أننا نريد من الحزمة <code>creature</code> التعامل مع دالة عشوائية، افتح هذا الملف:
</p>

<pre class="ipsCode">$ nano creature/creature.go
</pre>

<p>
	أضف التعليمات التالية إليه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_17" style=""><span class="pln">package creature

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"math/rand"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

var creatures </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"octopus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dolphin"</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Random</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    rand</span><span class="pun">.</span><span class="typ">Seed</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">UnixNano</span><span class="pun">())</span><span class="pln">
    i </span><span class="pun">:=</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">creatures</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> creatures</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استوردنا في هذا البرنامج الحزمة <code>time</code> واستخدمنا الدالة <code>()Seed</code> لضبط مفتاح توليد الأعداد seed في الحزمة إلى وقت التنفيذ آنذاك. احفظ وأغلق الملف.
</p>

<p>
	الآن بتشغيل البرنامج:
</p>

<pre class="ipsCode">$ go run cmd/main.go
</pre>

<p>
	ستحصل على ما يلي:
</p>

<pre class="ipsCode">jellyfish
octopus
shark
jellyfish
</pre>

<p>
	إذا شغلت البرنامج عدة مرات، فستحصل على نتائج مختلفة في كل مرة، وعمومًا هذا ليس نهجًا مثاليًا لأن الدالة <code>()creature.Random</code> تُستدعى في كل مرة ولأنه يُعاد ضبط مفتاح توليد الأعداد من خلال الاستدعاء <code>(()rand.Seed(time.Now().UnixNano</code>، وإعادة ضبط مفتاح التوليد re-seeding باستمرار قد يصادف استعمال قيمتين متماثلتين في حالتنا لو استدعي أكثر من مرة بدون تغير الوقت، أي إذا لم تتغير الساعة الداخلية، وهذا سيؤدي إلى تكرار محتمل للنمط العشوائي أو سيزيد من وقت المعالجة في وحدة المعالجة المركزية عن طريق جعل البرنامج ينتظر حتى تتغير الساعة الداخلية، ولحل هذه المشكلة يمكننا استخدام الدالة <code>()init</code>، لذا سنعدّل الملف creature.go:
</p>

<pre class="ipsCode">$ nano creature/creature.go
</pre>

<p>
	أضف ما يلي إلى الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_19" style=""><span class="pln">package creature

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"math/rand"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

var creatures </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"jellyfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"octopus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dolphin"</span><span class="pun">}</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    rand</span><span class="pun">.</span><span class="typ">Seed</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">UnixNano</span><span class="pun">())</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Random</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    i </span><span class="pun">:=</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">creatures</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> creatures</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إضافة الدالة <code>()init</code> ستخبر المصرِّف أنه يجب استدعاؤها عند استيراد الحزمة <code>creature</code> ولمرة واحدة فقط، وبالتالي يكون لدينا مفتاح توليد seed واحد لتوليد العدد العشوائي، ويجنبنا هذا النهج تكرار تنفيذ <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">التعليمات البرمجية</a>، والآن إذا أعدنا تشغيل الشيفرة عدة مرات، فسنحصل على نتائج مختلفة:
</p>

<pre class="ipsCode">$ go run cmd/main.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">dolphin
squid
dolphin
octopus
</pre>

<p>
	رأينا في هذا القسم كيف يمكّننا استخدام الدالة <code>()init</code> من إجراء العمليات الحسابية أو التهيئة المناسبة قبل استخدام الحزمة، وسنرى فيما يلي كيف يمكننا استخدام عدة تعليمات تهيئة <code>()init</code> في حزمة ما.
</p>

<h2>
	استخدام عدة تعليمات من ()init
</h2>

<p>
	يمكن التصريح عن الدالة <code>()init</code> أكثر من مرة ضمن الحزمة على عكس الدالة <code>()main</code> التي لا يمكن التصريح عنها إلا مرةً واحدةً، وعمومًا يؤدي وجود أكثر من دالة تهيئة إلى حدوث التباس في أولوية التنفيذ، أي مَن يُنفَّذ أولًا ومَن لا يُنفَذ، لذا سيوضح هذا القسم كيفية استخدام تعليمات تهيئة متعددة وكيفية التحكم بها.
</p>

<p>
	ستُنفّذ عادةً دوال <code>init()‎</code> بالترتيب نفسه الذي تظهر فيه في الشيفرة مثل ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_21" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"First init"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Second init"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Third init"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Fourth init"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	لنُشغّل البرنامج كما يلي:
</p>

<pre class="ipsCode">$ go run main.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">First init
Second init
Third init
Fourth init
</pre>

<p>
	لاحظ أنّ تعليمات التهيئة قد نُفِّذت حسب الترتيب الذي وجدها فيه المصرِّف، وعمومًا قد لا يكون من السهل دائمًا تحديد الترتيب الذي ستُنفّذ فيه تعليمات التهيئة، ففي المثال التالي سنعرض حزمةً أكثر تعقيدًا تتضمن عدة ملفات وكل ملف لديه دالة تهيئة خاصة به. لتوضيح الأمر سننشئ برنامجًا يشارك متغيرًا اسمه <code>message</code> ويطبعه، والآن احذف مجلدات creature و cmd ومحتوياتهما واستبدلهما بالمجلدات وبنية الملف التالية:
</p>

<pre class="ipsCode">├── cmd
│   ├── a.go
│   ├── b.go
│   └── main.go
└── message
    └── message.go
</pre>

<p>
	سنضع الآن محتويات كل ملف في a.go، لذا أضف الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_23" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/message"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"a -&gt;"</span><span class="pun">,</span><span class="pln"> message</span><span class="pun">.</span><span class="typ">Message</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتضمن الملف دالة تهيئة واحدة تطبع قيمة <code>message.Message</code> من الحزمة <code>message</code>، والآن أضف الأسطر التالية في b.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_25" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/message"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    message</span><span class="pun">.</span><span class="typ">Message</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"b -&gt;"</span><span class="pun">,</span><span class="pln"> message</span><span class="pun">.</span><span class="typ">Message</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لدينا في هذا الملف دالة تهيئة واحدة تُسند السلسلة <code>Hello</code> إلى المتغير <code>message.Message</code> وتطبعها، والآن أنشئ الآن ملف main.go كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_27" style=""><span class="pln">package main
func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	هذا الملف لا يفعل شيئًا، ولكنه يوفر نقطة دخول للبرنامج لكي يُنفّذ، والآن أنشئ ملف message.go:
</p>

<pre class="ipsCode">package message
var Message string
</pre>

<p>
	تُصرّح حزمة <code>message</code> عن المتغير المُصدّر <code>Message</code>، ولتشغيل البرنامج نفّذ الأمر التالي من مجلد cmd:
</p>

<pre class="ipsCode">$ go run *.go
</pre>

<p>
	نحتاج إلى إخبار المصرِّف بأنه يجب تصريف جميع ملفات <code>go.</code> الموجودة في مجلد cmd نظرًا لوجود العديد من ملفات جو في مجلد cmd الذي يُشكّل الحزمة الرئيسية <code>main</code>، فمن خلال كتابة <code>go.*</code> يمكننا إخبار المُصرّف أنه عليه تحميل كل الملفات التي لاحقتها <code>go.</code> في مجلد cmd، وإذا شغّلنا الأمر <code>go run main.go</code>، فسيفشل البرنامج في التصريف لأنه لن يرى ملفَي a.go و b.go، وسنحصل على الخرج التالي:
</p>

<pre class="ipsCode" id="ips_uid_243_33">a -&gt;
b -&gt; Hello</pre>

<p>
	وفقًا لقواعد <a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%81%D9%8A-%D8%AC%D9%88-go-r1788/" rel="">لغة جو</a> في تهيئة الحزم، فإنه عند مصادفة عدة ملفات في الحزمة نفسها، ستكون أفضلية المعالجة وفق الترتيب الأبجدي alphabetical، لذا في أول مرة طبعنا فيها <code>message.Message</code> من a.go كانت القيمة المطبوعة هي القيمة الفارغة، وستبقى فارغةً طالما لم تُهيئ من خلال الدالة <code>()init</code> في الملف b.go، وإذا أردنا تغيير اسم ملف a.go إلى c.go، فسنحصل على نتيجة مختلفة:
</p>

<pre class="ipsCode" id="ips_uid_243_35">b -&gt; Hello
a -&gt; Hello</pre>

<p>
	الآن أصبح المصّرِف يرى الملف b.go أولًا، وبالتالي أصبحت قيمة <code>message.Message</code> مُهيّئة بالقيمة <code>Hello</code> وذلك بعد تنفيذ الدالة <code>()init</code> في ملف c.go.
</p>

<p>
	لاحظ أنّ هذا السلوك قد يخلق أخطاءً و مشاكل لاحقة لأنه من الشائع تغيير أسماء الملفات أثناء تطوير أيّ مشروع، وهذا يؤثر على ترتيب تنفيذ دالة التهيئة كما أوضحنا.
</p>

<p>
	يفضَّل تقديم الملفات المتعددة الموجودة ضمن الحزمة نفسها ضمن ملف واحد بترتيب مُعجمي lexical order إلى المصرِّف للتحكم بنهج التهيئة المتعدد، وبالتالي ضمان أنّ كل دوال التهيئة تُحمّل من أجل التصريح عنها في ملف واحد، وبالتالي منع تغيير ترتيب تنفيذها حتى لو تغيرت الأسماء.
</p>

<p>
	يجب أن تحاول أيضًا تجنب إدارة الحالة managing state في الحزمة الخاصة بك باستخدام المتغيرات العامة، أي المتغيرات التي يمكن الوصول إليها من أيّ مكان في الحزمة، ففي البرنامج السابق مثلًا كان المتغير <code>message.Message</code> مُتاحًا في أيّ مكان ضمن الحزمة مع الحفاظ على حالة البرنامج، وبسبب هذه الإمكانية كانت دوال التهيئة قادرةً على الوصول إلى هذا المتغير وتعديل قيمته، وبالتالي أصبح من الصعب التنبؤ بسلوك هذا البرنامج، ولتجنب ذلك يُفضَّل إبقاء المتغيرات ضمن مساحات يمكنك التحكم بها مع إمكانية وصول ضئيلة لها قدر الإمكان حسب حاجة البرنامج.
</p>

<p>
	قد يؤدي وجود عدة تعليمات تهيئة ضمن البرنامج إلى ظهور تأثيرات غير مرغوب فيها ويجعل من الصعب قراءة برنامجك أو التنبؤ به، كما يضمن لك تجنب استخدام تعليمات التهيئة المتعددة أو الاحتفاظ بها جميعًا في ملف واحد بعدم تغير سلوك برنامجك عند نقل الملفات أو تغيير الأسماء.
</p>

<h2>
	استخدام دالة التهيئة لتحقيق مفهوم التأثير الجانبي
</h2>

<p>
	غالبًا ما تستورَد بعض الحزم في لغة جو بغية الاستفادة من تأثيرها الجانبي فقط وليس من أجل أيّ مكوِّن آخر من مكوناتها، وغالبًا ما يكون ذلك عندما تتضمن هذه الحزمة دالة تهيئة بداخلها، وبالتالي تُنفّذ قبل أيّ شيفرة أخرى بمجرد استيراد الحزمة، وبالتالي إمكانية التلاعب بالحالة التي يبدأ بها البرنامج، وتسمى هذه العملية باستيراد التأثير الجانبي.
</p>

<p>
	إحدى حالات الاستخدام الشائعة لمفهوم استيراد التأثير الجانبي هي الحصول على معلومات أولية تُفيد في تحديد أي جزء من شيفرة ما يجب أن يُنفّذ، ففي حزمة <code>image</code> مثلًا تحتاج الدالة <code>image.Decode</code> إلى معرفة تنسيق الصورة التي تحاول فك تشفيرها (jpg ،png ،gif، …إلخ) قبل أن تتمكن من تنفيذها، وهكذا أمر يمكن تحقيقه من خلال مفهوم التأثير الجانبي، فلنقل أنك تحاول استخدام <code>image.Decode</code> مع ملف بتنسيق png كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_37" style=""><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
func decode</span><span class="pun">(</span><span class="pln">reader io</span><span class="pun">.</span><span class="typ">Reader</span><span class="pun">)</span><span class="pln"> image</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    m</span><span class="pun">,</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> image</span><span class="pun">.</span><span class="typ">Decode</span><span class="pun">(</span><span class="pln">reader</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> m</span><span class="pun">.</span><span class="typ">Bounds</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></pre>

<p>
	هذا البرنامج سليم من ناحية التصريف، لكن إذا حاولت فك تشفير صورة بتنسيق png، فستتلقى خطأً، ولحل هذه المشكلة سنحتاج إلى تسجيل تنسيق الصورة في الدالة <code>image.Decode</code>، ولحسن الحظ تتضمن الحزمة <code>image/png</code> تعليمة التهيئة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_243_39" style=""><span class="pln">func init</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    image</span><span class="pun">.</span><span class="typ">RegisterFormat</span><span class="pun">(</span><span class="str">"png"</span><span class="pun">,</span><span class="pln"> pngHeader</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Decode</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DecodeConfig</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبالتالي إذا استوردنا <code>image/png</code> إلى الشيفرة السابقة، فستُنفَّذ دالة التهيئة <code>()image.RegisterFormat</code> مباشرةً وقبل أيّ شيء آخر.
</p>

<pre class="ipsCode">. . .
import _ "image/png"
. . .

func decode(reader io.Reader) image.Rectangle {
    m, _, err := image.Decode(reader)
    if err != nil {
        log.Fatal(err)
    }
    return m.Bounds()
}
</pre>

<p>
	سيؤدي هذا إلى ضبط حالة البرنامج وتسجيل أننا نحتاج إلى إصدار png من <code>image.Decode()‎</code>، وسيحدث هذا التسجيل بوصفه أثرًا جانبيًا لاستيراد الحزمة <code>image/png</code>.
</p>

<p>
	ربما لاحظت وجود الشرطة السفلية <code>_</code> قبل <code>"image/png"</code>، فهذا أمر مهم لأنّ جو لا تسمح لك باستيراد حزمة غير مستخدَمة في البرنامج، وبالتالي فإنّ وجود الشرطة السفلية سيتجاهل أيّ شيء في الحزمة المستورَدة باستثناء تعليمة التهيئة -أي التأثير الجانبي-، وهذا يعني أنه حتى إذا لم نستورِد الحزمة <code>image/png</code>، فيمكننا استيراد تأثيرها الجانبي.
</p>

<p>
	من المهم أن تعرف متى تحتاج إلى استيراد حزمة للحصول على تأثيرها الجانبي، فبدون التسجيل الصحيح، من المحتمل أن تتمكن جو من تصريف برنامجك ولكن لن يعمل كما تتوقع، وعادةً ما تتضمن مراجع (أو توثيقات documentation) المكتبة القياسية إشارةً إلى الحاجة إلى هكذا نوع من التأثيرات مع حالات معينة، وبالتالي إذا كتبت حزمةً تتطلب استيرادًا للتأثيرات الجانبية، فيجب عليك أيضًا التأكد من توثيق دالة التهيئة التي تستخدِمها حتى يتمكن المستخدِمون الذين يستورِدون الحزمة الخاصة بك من استخدامها بطريقة صحيحة.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعلّمنا في هذا المقال استخدام دالة التهيئة <code>()init</code> وفهمنا كيف أنها تُنفَّذ قبل أيّ شيء آخر في البرنامج وأنها تستطيع أداء بعض المهام وضبط حالة البرنامج الأولية، كما تحدّثنا أيضًا عن تعليمات التهيئة المتعددة والموجودة ضمن ملفات متعددة وكيف أنّ ترتيب تنفيذها يعتمد على على أمور محددة مثل الترتيب الأبجدي أو المعجمي لملفات الحزمة.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-init-in-go" rel="external nofollow">Understanding init in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-defer-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1963/" rel="">التعليمة defer في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D9%88%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1962/" rel="">كيفية تعريف واستدعاء الدوال في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1964</guid><pubDate>Thu, 27 Apr 2023 16:07:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x629; defer &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-defer-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1963/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/-defer----Go.png.f8c20470196754508fa4150b7fcb2ca6.png" /></p>
<p>
	تتضمن لغة جو العديد من تعليمات التحكم بسير عمل البرنامج مثل <code>if</code> و <code>switch</code> و <code>for</code> …إلخ، وهذه التعليمات موجودة في أغلب <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a>، إلا أنّ هناك تعليمة خاصة في لغة جو غير موجودة في معظم اللغات الأخرى هي تعليمة التأجيل <code>defer</code>.
</p>

<p>
	على الرغم من أن هذه التعليمة ليست مشهورة إلا أنها مفيدة، فالهدف الأساسي من هذه التعليمة هو إجراء عملية تنظيف الموارد بطريقة سليمة بعد انتهاء استخدامها مثل الملفات المفتوحة أو الاتصالات بالشبكة أو مقابض قاعدة البيانات handles بعد تأجيلها ريث الانتهاء منها، إذ تُعَدّ عملية تنظيف أو تحرير الموارد بعد استخدامها أمرًا مهمًا جدًا للسماح للمستخدِمين الآخرين باستخدام هذا المورد دون وجود أي بقايا تركها المستخدِم السابق سواءً كان المستخدِم آلةً أو شخصًا أو برنامجًا أو جزءًا آخر من الشيفرة نفسها.
</p>

<p>
	تساعدنا تعليمة التأجيل <code>defer</code> في جعل الشيفرة أنظف وأكثر متانةً وأقل عرضةً للأخطاء من خلال جعل تعليمة استدعاء أو حجز الملف أو المورد قريبة من تعليمة تحريره، وفي هذا المقال سنتعلم كيفية استخدام تعليمة التأجيل <code>defer</code> بطريقة صحيحة لتنظيف الموارد بالإضافة إلى العديد من الأخطاء الشائعة التي تحدث عند استخدام هذه التعليمة.
</p>

<h2>
	ما هي تعليمة defer؟
</h2>

<p>
	تسمح لك جو بتأجيل تنفيذ استدعاء دالة بإضافتها إلى طابور تنفيذ خاص ريثما تكون الدالة المُستدعاة ضمنها قد أكتمل تنفيذها من خلال استخدام الكلمة المفتاحية <code>defer</code> قبلها بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_8" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Bye"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أجّلنا هنا استخدام الدالة <code>("fmt.Println("Bye</code> إلى حين انتهاء تنفيذ الدالة المُستدعاة ضمنها أي الدالة <code>main</code>، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Hi
Bye
</pre>

<p>
	أي سيُنفّذ هنا كل شيء داخل الدالة <code>main</code> ثم بعد الانتهاء من كل التعليمات (هنا لا توجد إلا تعليمة واحدة هي التعليمة التي تطبع <code>Hi</code>) ستُنفَّذ التعليمة المؤجلة، كما رأيت بالمثال.
</p>

<p>
	والآن قد يتبادر إلى الأذهان السؤال التالي: ماذا لو كان هناك أكثر من استدعاء مؤجل، أي أكثر من دالة مؤجلة، ماذا سيحدث؟ كل دالة تُسبق بتعليمة التأجيل تُضاف إلى مكدس، ومن المعروف أنّ المكدس هو بنية معطيات تخرج منها البيانات وفق مبدأ مَن يدخل آخرًا يخرج أولًا، وبالتالي إذا كان لدينا أكثر من استدعاء مؤجل، فسيكون التنفيذ وفق هذه القاعدة، ولجعل الأمور أبسط سنأخذ المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_10" style=""><span class="pln">package main
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">
func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Bye1"</span><span class="pun">)</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Bye2"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Hi
Bye2
Bye1
</pre>

<p>
	لدينا في البرنامج السابق استدعاءان مؤجلان، إذ يُضاف أولًا إلى المكدس التعليمة التي تطبع <code>Bye1</code> ثم التعليمة التي تطبع <code>Bye2</code>، ووفق القاعدة السابقة ستُطبع التعليمة التي أٌضيفت أخيرًا إلى المكدس أي <code>Bye2</code> ثم <code>Bye1</code>، وبالطبع تُنفَّذ التعليمة التي تطبع <code>Hi</code> وأيّ تعليمة أخرى ضمن الدالة <code>main</code> قبل تنفيذ أيّ تعليمة مؤجلة، ولدينا مثال آخر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi0"</span><span class="pun">)</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Bye1"</span><span class="pun">)</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Bye2"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi1"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi2"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Hi0
Hi1
Hi2
Bye2
Bye1
</pre>

<p>
	عند تأجيل تنفيذ دالة ما ستقيَّم الوسائط على الفور، وبالتالي لن يؤثر أيّ تعديل لاحق، لذا انتبه جيدًا إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_14" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">9
</pre>

<p>
	كانت هنا قيمة <code>x</code> تساوي 9 ثم أجلنا تنفيذ دالة الطباعة التي تطبع قيمة هذا المتغير، وعلى الرغم من أنّ تعليمة <code>x=10</code> ستُنفَّذ قبل تعليمة الطباعة، إلا أنّ القيمة التي طُبعَت هي القيمة السابقة للمتغير <code>x</code> وذلك للسبب الذي ذكرناه منذ قليل.
</p>

<p>
	ما تعلمناه حتى الآن كان بغرض التوضيح فقط، إذ لا تُستخدم بهذا الشكل بل عادة ما تُستخدم تعليمة التأجيل في تنظيف الموارد وهذا ما سنراه تاليًا.
</p>

<h2>
	تنظيف الموارد باستخدام تعليمة التأجيل
</h2>

<p>
	يُعَدّ استخدام تعليمة التأجيل لتنظيف الموارد أمرًا شائعًا جدًا في جو، وسنلقي الآن نظرةً على برنامج يكتب سلسلةً نصيةً في ملف ولكنه لا يستخدِم تعليمة التأجيل لتنظيف المورد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_16" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"readme.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"This is a readme file"</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to write file:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func write</span><span class="pun">(</span><span class="pln">fileName string</span><span class="pun">,</span><span class="pln"> text string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    file</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">WriteString</span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> nil
</span><span class="pun">}</span></pre>

<p>
	لدينا في هذا البرنامج دالة تسمى <code>write</code> والهدف منها بدايةً هو محاولة إنشاء ملف، وإذا حصل خطأ أثناء هذه المحاولة، فستُعيد هذا الخطأ وتُنهي التنفيذ؛ أما في حال نجاح عملية إنشاء الملف، فستكتب فيه السلسلة <code>This is a readme file</code>، وفي حال فشلت عملية الكتابة، فستُعيد الخطأ وتنهي تنفيذ الدالة أيضًا، وأخيرًا إذا نجح كل شيء، فستغلق الدالة الملف الذي أُنشِئ معيدة إياه إلى <a href="https://academy.hsoub.com/devops/servers/databases/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%88%D8%A7%D8%AE%D8%AA%D9%84%D8%A7%D9%81%D9%87-%D8%B9%D9%86-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r509/" rel="">نظام الملفات</a> ثم تُعيد القيمة <code>nil</code> إشارةً إلى نجاح التنفيذ.
</p>

<p>
	هذا البرنامج يعمل بطريقة سليمة، إلا أنّ هناك زلة برمجية صغيرة؛ فإذا فشلت عملية الكتابة في الملف، فسيبقى الملف المُنشئ مفتوحًا، أي توجد هناك موارد غير محررة، ولحل هذه المشكلة مبدأيًا يمكنك تعليمة <code>file.Close()‎</code> أخرى ومن دون استخدام تعليمة التأجيل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_18" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"readme.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"This is a readme file"</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to write file:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func write</span><span class="pun">(</span><span class="pln">fileName string</span><span class="pun">,</span><span class="pln"> text string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    file</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">WriteString</span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> nil
</span><span class="pun">}</span></pre>

<p>
	الآن سيُغلق الملف حتى إذا فشل تنفيذ <code>io.WriteString</code>، وقد يكون هذا حلًا بسيطًا وأسهل من غيره، لكن إذا كانت الدوال أكثر تعقيدًا، فقد ننسى إضافة هكذا تعليمات في الأماكن المُحتملة التي قد ينتهي فيها التنفيذ قبل تحرير المورد، لذا يتمثّل الحال الأكثر احترافيةً وأمانًا باستخدام تعليمة التأجيل مع الدالة <code>file.Close</code> وبالتالي ضمان تنفيذها دومًا بغض النظر عن أيّ مسار تنفيذ أو <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/" rel="">خطأ مُفاجئ</a> قد يؤدي إلى إنهاء الدالة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_20" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"readme.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"This is a readme file"</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to write file:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func write</span><span class="pun">(</span><span class="pln">fileName string</span><span class="pun">,</span><span class="pln"> text string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    file</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    defer file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">WriteString</span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> nil
</span><span class="pun">}</span></pre>

<p>
	أضفنا هنا السطر <code>defer file.Close</code> لإخبار المُصرّف بإغلاق الملف بعد انتهاء تنفيذ الدالة، وبالتالي ضمان تحريره مهما حدث.
</p>

<p>
	انتهينا هنا من زلة برمجية ولكن ستظهر لنا <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B2%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1245/" rel="">زلة برمجية</a> أخرى؛ ففي حال حدث خطأ في عملية إغلاق الملف <code>file.Close</code>، فلن تكون هناك أيّ معلومات حول ذلك الخطأ، أي لن يُعاد الخطأ، وبالتالي يمنعنا استخدام تعليمة التأجيل من الحصول على الخطأ أو الحصول على أيّ قيمة تُعيدها الدالة المؤجلة.
</p>

<p>
	يُعَدّ استدعاء الدالة <code>Close</code> في جو أكثر من مرة آمنًا ولا يؤثر على سلوك البرنامج، وفي حال كان هناك خطأ، فسيُعاد من المرة الأولى التي تُستدعى فيها الدالة، وبالتالي سيسمح لنا هذا باستدعائها ضمن مسار التنفيذ الناجح في الدالة.
</p>

<p>
	سنعالج في المثال التالي المشكلة السابقة التي تتجلى بعدم إمكانية الحصول على معلومات الخطأ في حال حدوثه مع تعليمة الإغلاق المؤجلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_22" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"readme.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"This is a readme file"</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to write file:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func write</span><span class="pun">(</span><span class="pln">fileName string</span><span class="pun">,</span><span class="pln"> text string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    file</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    defer file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">WriteString</span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أنّ التعديل الوحيد على الشيفرة السابقة كان بإضافة السطر <code>return file.Close()‎</code>، وبالتالي إذا حصل خطأ في عملية الإغلاق، فسيُعاد مباشرةً إلى الدالة التي تستدعي الدالة <code>write</code>، ولاحظ أيضًا أنّ التعليمة <code>defer file.Close</code> ستُنفّذ بكافة الأحوال، مما يعني أنّ تعليمة الإغلاق ستُنفّذ مرتين غالبًا، وعلى الرغم من أنّ ذلك ليس مثاليًّا، إلا أنه مقبول وآمن.
</p>

<p>
	إذا ظهر خطأ في تعليمة <code>WriteString</code>، فسيُعاد الخطأ وينتهي تنفيذ الدالة ثم ستُنفّذ تعليمة <code>file.Close</code> لأنها تعليمة مؤجلة، وهنا على الرغم من إمكانية ظهور خطأ عند محاولة إغلاق الملف، إلا أنّ هذا الخطأ لم يَعُد مهمًا لأن الخطأ الذي تعيده <code>WriteString</code> سيكون غالبًا هو السبب وراء حدوثه.
</p>

<p>
	تعرّفنا حتى الآن على كيفية استخدام تعليمة التأجيل واحدة لضمان تحرير أو تنظيف مورد ما، وسنتعلّم الآن كيفية استخدام عدة تعليمات تأجيل من أجل تنظيف أكثر من مورد.
</p>

<h2>
	استخدام تعليمات تأجيل متعددة
</h2>

<p>
	من الطبيعي أن تكون لديك أكثر من تعليمة <code>defer</code> في دالة ما، لذا دعنا ننشئ برنامجًا يحتوي على تعليمات تأجيل فقط لنرى ما سيحدث في هذه الحالة (كما أشرنا سابقًا):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_24" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"one"</span><span class="pun">)</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"two"</span><span class="pun">)</span><span class="pln">
    defer fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"three"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">three
two
one
</pre>

<p>
	كما ذكرنا سابقًا أنّ سبب الطباعة بهذا الترتيب هو أن تعليمة التأجيل تعتمد على تخزين سلسلة الاستدعاءات ضمن بنية المكدس، والمهم الآن أن تعرف أنه يمكن أن يكون لديك العديد من الاستدعاءات المؤجلة حسب الحاجة في دالة ما، ومن المهم أن تتذكر أنها تُستدعى جميعها بعكس ترتيبها في الشيفرة حسب بنية المكدس.
</p>

<p>
	الآن بعد أن فهمنا هذه الفكرة جيدًا، سننشئ برنامجًا يفتح ملفًا ويكتب عليه ثم يفتحه مرةً أخرى لنسخ المحتويات إلى ملف آخر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5842_26" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"sample.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"This file contains some sample text."</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to create file"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> fileCopy</span><span class="pun">(</span><span class="str">"sample.txt"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"sample-copy.txt"</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="str">"failed to copy file: %s"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func write</span><span class="pun">(</span><span class="pln">fileName string</span><span class="pun">,</span><span class="pln"> text string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    file</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    defer file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">WriteString</span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> file</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func fileCopy</span><span class="pun">(</span><span class="pln">source string</span><span class="pun">,</span><span class="pln"> destination string</span><span class="pun">)</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    src</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Open</span><span class="pun">(</span><span class="pln">source</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    defer src</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    dst</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Create</span><span class="pun">(</span><span class="pln">destination</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    defer dst</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    n</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> io</span><span class="pun">.</span><span class="typ">Copy</span><span class="pun">(</span><span class="pln">dst</span><span class="pun">,</span><span class="pln"> src</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Copied %d bytes from %s to %s\n"</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">,</span><span class="pln"> destination</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> src</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">();</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> dst</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لدينا هنا دالة جديدة <code>fileCopy</code> تفتح أولًا ملف المصدر الذي سننسخ منه ثم تتحقق من حدوث خطأ أثناء فتح الملف، فإذا كان الأمر كذلك، فسنعيد الخطأ ونخرج من الدالة، وإلا فإننا نؤجل إغلاق الملف المصدر الذي فتحناه.
</p>

<p>
	نُنشئ بعد ذلك ملف الوجهة ونتحقق من حدوث خطأ أثناء إنشاء الملف، فإذا كان الأمر كذلك، فسنعيد هذا الخطأ ونخرج من الدالة، وإلا فسنؤجل أيضًا إغلاق ملف الوجهة، وبالتالي لدينا الآن دالتان مؤجلتان ستُستدعيان عندما تخرج الدالة من نطاقها.
</p>

<p>
	الآن بعد فتح كل من ملف المصدر والوجهة فإننا سننسخ <code>()Copy</code> البيانات من الملف المصدر إلى الملف الوجهة، فإذا نجح ذلك، فسنحاول إغلاق كلا الملفين، وإذا تلقينا خطأً أثناء محاولة إغلاق أيّ ملف، فسنُعيد الخطأ ونخرج من الدالة.
</p>

<p>
	لاحظ أننا نستدعي <code>()Close</code> لكل ملف صراحةً على الرغم من أنّ تعليمة التأجيل ستستدعيها أيضًا، والسبب وراء ذلك هو كما ذكرناه في الفقرة السابقة؛ وهو للتأكد من أنه إذا كان هناك خطأ في إغلاق ملف، فإننا نُعيد معلومات هذا الخطأ، كما يضمن أنه إذا أُنهيَت الدالة مُبكرًا لأيّ سبب من الأسباب بسبب خطأ ما مثل الفشل في عملية النسخ بين الملفين، فسيحاول كل ملف الإغلاق بطريقة سليمة من خلال تنفيذ الاستدعاءات المؤجلة.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تحدثنا في هذا المقال عن تعليمة التأجيل <code>defer</code> وكيفية استخدامها والتعامل معها وأهميتها في تنظيف وتحرير الموارد بعد الانتهاء من استخدامها، وبالتالي ضمان توفير الموارد للمستخدِمين المختلفِين وتوفير الذاكرة.
</p>

<p>
	يمكنك أيضًا الرجوع إلى مقال <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%86%D9%87%D9%8A%D8%A7%D8%B1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1901/" rel="">معالجة حالات الانهيار في لغة جو Go</a>: يتضمن حالةً خاصةً من حالات استخدام تعليمة التأجيل.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-defer-in-go" rel="external nofollow">Understanding defer in Go </a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D9%88%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1962/" rel="">كيفية تعريف واستدعاء الدوال في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">كيفية كتابة التعليمات الشرطية if في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%81%D8%B5%D9%84-%D8%A7%D9%84%D8%B1%D8%A7%D8%A8%D8%B9-%D9%81%D9%87%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-files-%D9%88%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-file-systems-r979/" rel="">فهم الملفات Files وأنظمة الملفات file systems</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1963</guid><pubDate>Tue, 25 Apr 2023 15:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x639;&#x631;&#x64A;&#x641; &#x648;&#x627;&#x633;&#x62A;&#x62F;&#x639;&#x627;&#x621; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D9%88%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1962/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/-------Go.png.391ad082ff8a89e3ba55aec093108e37.png" /></p>
<p>
	تُعَدّ الدالة funtion كتلةً من التعليمات التي تنفِّذ إجراءً ما، ويمكن بعد تعريفها إعادة استخدامها في أكثر من موضع. تجعل الدوال الشيفرة تركيبية modular، مما يسمح بتقسيم الشيفرة إلى أجزاء صغيرة سهلة الفهم واستخدامها مرارًا وتكرارًا. تضم لغة جو مكتبةً قياسيةً تدعى <code>fmt</code>، إذ تحتوي على عدد من الدوال المُضمّنة التي قد تكون شائعة بالنسبة لك مثل:
</p>

<ul>
	<li>
		الدالة <code>()fmt.Println</code> تُستخدَم للطباعة على شاشة الخرج القياسية المُستخدَمة.
	</li>
	<li>
		الدالة <code>()fmt.Printf</code> تُستخدَم للطباعة مع إمكانية تنسيق الخرج.
	</li>
</ul>

<p>
	تتضمن أسماء الدوال الأقواس وقد تتضمن معامِلات أيضًا، وسنتعلم في هذا المقال كيفية تعريف الدوال وكيفية استخدامها في البرامج.
</p>

<h2>
	تعريف الدالة
</h2>

<p>
	لنبدأ بتحويل برنامج <a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%81%D9%8A-%D8%AC%D9%88-go-r1788/" rel="">"Hello, World!‎"</a> إلى دالة، لذا أنشئ ملفًا نصيًا جديدًا وافتحه في محرر النصوص المفضل عندك ثم استدع البرنامج ‎hello.go.
</p>

<p>
	تُعرَّف الدالة باستخدام الكلمة المفتاحية <code>func</code> متبوعة باسم من اختيارك ثم قوسين يمكن أن يَحتويا المعامِلات التي ستأخذها الدالة ثم ينتهي التعريف بنقطتين، وسنعرّف هنا دالةً باسم <code>‎‎</code>hello()‎‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_8" style=""><span class="pln">func hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	أعددنا في الشفرة أعلاه تعليمة التهيئة لإنشاء الدالة، وبعد ذلك سنضيف سطرًا ثانيًا مُزاحًا بأربع مسافات بيضاء ثم سنكتب التعليمات التي ستنفّذها الدالة، وفي هذه الحالة سنطبع العبارة <code>!Hello, World</code> في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_10" style=""><span class="pln">func hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أتممنا تعريف دالتنا ولكن إذا نَفَّذنا البرنامج الآن، فلن يحدث أيّ شيء لأننا لم نستدع الدالة، لذلك سنستدعي الدالة ‎<code>hello()</code>‎ ضمن الدالة <code>()main</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    hello</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لننفّذ البرنامج الآن كما يلي:
</p>

<pre class="ipsCode">$ go run hello.go
</pre>

<p>
	يجب أن تحصل على الخرج التالي:
</p>

<pre class="ipsCode">Hello, World!
</pre>

<p>
	الدالة <code>()main</code> هي دالة خاصة تخبر المُصرّف أنّ هذا هو المكان الذي يجب أن يبدأ منه البرنامج، فأيّ برنامج تريده أن يكون قابلاً للتنفيذ (برنامج يمكن تشغيله من الطرفية)، فستحتاج إلى دالة <code>()main</code>، كما يجب أن تظهر الدالة <code>()main</code> مرةً واحدةً فقط وأن تكون في الحزمة <code>main</code> ولا تستقبل أو تعيد أيّ وسائط، وهذا يسمح بتنفيذ البرنامج في أيّ برنامج جو آخر حسب المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_15" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"this is the main section of the program"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بعض الدوال أكثر تعقيدًا بكثير من الدالة ‎<code>hello()</code>‎ التي عرّفناها أعلاه، إذ يمكننا على سبيل المثال استخدام حلقة <code>for</code> والتعليمات الشرطية وغيرها داخل كتلة الدالة، فالدالة المُعرّفة أدناه على سبيل المثال تستخدِم تعليمةً شرطيةً للتحقق مما إذا كانت المدخلات الممرّرة إلى المتغير <code>‎name‎</code> تحتوي على حرف صوتي vowel، ثم تستخدِم الحلقة <code>‎for‎</code> للتكرار على الحروف الموجودة في السلسلة النصية <code>‎name‎</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_17" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    names</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func names</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Enter your name:"</span><span class="pun">)</span><span class="pln">

    var name string
    fmt</span><span class="pun">.</span><span class="typ">Scanln</span><span class="pun">(&amp;</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// Check whether name has a vowel</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range strings</span><span class="pun">.</span><span class="typ">ToLower</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> </span><span class="str">'a'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> </span><span class="str">'e'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> </span><span class="str">'i'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> </span><span class="str">'o'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> </span><span class="str">'u'</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Your name contains a vowel."</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Your name does not contain a vowel."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تستخدِم الدالة ‎names()<code>‎</code> التي عرّفناها أعلاه <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">تعليمةً شرطيةً</a> وحلقة <code>‎for‎</code>، وهذا توضيح لكيفية تنظيم الشيفرة البرمجية ضمن تعريف الدالة، كما يمكننا أيضًا جعل التعليمة الشرطية والحلقة <code>‎for‎</code> دالتين منفصلتين. يجعل تعريف الدوال داخل البرامج الشفرة البرمجية تركيبيةً modular وقابلةً لإعادة الاستخدام، وذلك سيتيح لنا استدعاء الدالة نفسها دون إعادة كتابة شيفرتها في كل مرة.
</p>

<h2>
	المعاملات
</h2>

<p>
	عرّفنا حتى الآن دالة ذات قوسين فارغين لا تأخذ أيّ وسائط arguments، وسنتعلم في هذا القسم كيفية تعريف المعامِلات parameters وتمرير البيانات إلى الدوال.
</p>

<p>
	يُعَدّ المعامِل كيانًا مُسمًّى يوضَع في تعريف الدالة ويعرِّف وسيطًا يمكن أن تقبله الدالة عند استدعائها، ويجب عليك في لغة Go أن تحدد <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1791/" rel="">نوع البيانات data type</a> لكل معامِل
</p>

<p>
	لننشئ برنامجًا يُكرر كلمة عدة مرات، إذ سنحتاج إلى متغير من النوع <code>string</code> سنسميه <code>word</code> ومتغير من النوع <code>int</code> سنسميه <code>reps</code> يُحدد عدد التكرارات.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_19" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    repeat</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func repeat</span><span class="pun">(</span><span class="pln">word string</span><span class="pun">,</span><span class="pln"> reps </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> reps</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">word</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مرّرنا السلسلة <code>Sammy</code> إلى المتغير <code>word</code> والقيمة 5 إلى المعامِل <code>reps</code> وذلك وفقًا لترتيب المعامِلات في ترويسة الدالة <code>repeat</code>، إذ تتضمّن الدالة حلقة <code>for</code> تطبع قيمة المعامِل <code>word</code> عدة مرات يُحدّدها المعامِل <code>reps</code>، وسيكون الخرج كما يلي:
</p>

<pre class="ipsCode">SammySammySammySammySammy
</pre>

<p>
	إذا كانت لديك مجموعة من المعامِلات وجميعها تمتلك القيمة نفسها، فيمكنك تجاهل تحديد النوع من أجل كل متغير كما سنرى، لذا دعنا ننشئ برنامجًا صغيرًا يأخذ ثلاثة معامِلات ‎<code>x</code>‎ و ‎y<code>‎</code> و <code>‎z‎</code> من النوع <code>int</code>، إذ سننشئ دالةً تجمع تلك المعامِلات وفق عدة مجموعات ثم تطبع الدالة حاصل جمعها.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_21" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    addNumbers</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func addNumbers</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> z </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    a </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> y
    b </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> z
    c </span><span class="pun">:=</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> z
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عند تعريف الدالة <code>addNumbers</code> لم نكن بحاجة إلى تحديد نوع كل متغير على حدة، وإنما وضعنا نوع بيانات كل المتغيرات مرةً واحدةً فقط.
</p>

<p>
	مرّرنا العدد ‎1‎ إلى المعامل ‎<code>x</code>‎ والعدد ‎2‎ إلى المعامل ‎<code>y</code>‎ والعدد ‎3‎ إلى المعامل ‎<code>z</code>‎، إذ تتوافق هذه القيم مع المعامِلات المقابلة لها في ترتيب الظهور، ويُجري البرنامج العمليات الحسابية على المعامِلات على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_23" style=""><span class="pln">a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3</span></pre>

<p>
	تطبع الدالة أيضًا ‎<code>a</code>‎ و ‎<code>b</code>‎ و <code>‎</code>c‎، وبناءً على العمليات الحسابية أعلاه، فستساوي قيمة ‎a<code>‎</code> العدد ‎3‎ و ‎b<code>‎</code> العدد ‎4‎ و ‎<code>c</code>‎ العدد ‎5‎، ولننفّذ البرنامج سنكتب ما يلي:
</p>

<pre class="ipsCode">$ go run add_numbers.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">3 4 5
</pre>

<p>
	عندما نمرر 1 و 2 و 3 على أساس معامِلات إلى الدالة <code>()addNumbers</code>، فإننا نتلقى الناتج المتوقع.
</p>

<p>
	تُعَدّ المعامِلات وسائط تُعرَّف عادة على أساس متغيرات ضمن تعريف الدالة، كما يمكن تعيين قيم إليها عند تنفيذ التابع بتمرير وسائط إلى الدالة.
</p>

<h2>
	إعادة قيمة
</h2>

<p>
	يمكن تمرير قيم إلى الدالة ويمكن كذلك أن تُنتج الدالة قيمةً وتُعيدها لمن استدعاها، إذ يمكن أن تنتج الدالة قيمةً عبر استخدام التعليمة <code>‎return‎</code> وهي تعليمة اختيارية، ولكن في حال استخدامها ستُنهي الدالة عملها مباشرةً وتوقف تنفيذها وتُمرَّر قيمة التعبير الذي يعقُبها اختياريًا إلى المستدعي، كما يجب تحديد نوع البيانات المُعادة أيضًا.
</p>

<p>
	استخدمنا حتى الآن الدالة <code>()fmt.Println‎</code> بدلاً من التعليمة <code>‎return‎</code> في دوالنا لطباعة شيء بدلًا من إعادته، فلننشئ برنامجًا يعيد متغيرًا بدلًا من طباعته مباشرةً، لذا سننشئ برنامجًا في ملف نصي جديد يسمى double.go‎ يحسب ناتج مُضاعفة المعامِل ‎<code>x</code>‎ ويُسند الناتج إلى المتغير ‎y<code>‎</code> ثم يعيده، كما سنطبع المتغير ‎<code>result</code>‎ والذي يساوي ناتج تنفيذ الدالة double(3)<code>‎</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_25" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    result </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="kwd">double</span><span class="pun">(</span><span class="pln">x </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    y </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> y
</span><span class="pun">}</span></pre>

<p>
	لننفّذ البرنامج كما يلي:
</p>

<pre class="ipsCode">$ go run double.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">6
</pre>

<p>
	خرج البرنامج هو العدد الصحيح ‎6 الذي أعادته الدالة وهو ما نتوقعه إذا طلبنا من جو حساب ناتج ضرب 2 بالعدد 3.
</p>

<p>
	إذا حددنا نوع القيمة المُعادة فيجب علينا إعادة قيمة من هذا النوع وإلا فسيُعطي البرنامج خطأً في التصريف، ففي المثال التالي سنلغي تعليمة الإعادة المُستخدَمة في الشيفرة السابقة بوضع تعليق على تعليمة الإعادة لكي يتجاهلها المُصرّف كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_27" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    result </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="kwd">double</span><span class="pun">(</span><span class="pln">x </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    y </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="com">// return y</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنحاول تنفيذ البرنامج:
</p>

<pre class="ipsCode">$ go run double.go
</pre>

<p>
	سيُشير الخرج إلى خطأ لأنه لم يجد تعليمة الإعادة <code>return</code>:
</p>

<pre class="ipsCode">./double.go:13:1: missing return at end of function
</pre>

<p>
	لا يمكن تصريف البرنامج بدون تعليمة الإعادة هذه، فعندما تصل الدالة إلى تعليمة <code>return</code> فإنها ستُنهي تنفيذ الدالة حتى إذا كان هناك تعليمات تالية ضمنها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_29" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    loopFive</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func loopFive</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">==</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">//i == 5 أوقف الدالة عندما </span><span class="pln">
          </span><span class="kwd">return</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"This line will not execute."</span><span class="pun">)</span><span class="pln"> </span><span class="com">// هذا السطر لن ينفَّذ</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستخدِم هنا حلقة <code>for</code> تُؤدي عملية تكرار 25 مرة وبداخلها تعليمة <code>if</code> تتحقق مما إذا كانت قيمة <code>i</code> تساوي العدد 5، فإذا كانت كذلك، فسيكون لدينا تعليمة <code>return</code> تُنهي تنفيذ الحلقة وتُنهي تنفيذ الدالة أيضًا، وهذا يعني أنّ باقي التكرارات لن تُنفّذ والسطر الأخير من الدالة <code>This line will not execute</code> لن يُنفّذ.
</p>

<p>
	يؤدي استخدام التعليمة <code>‎return‎</code> داخل الحلقة <code>‎for‎</code> إلى إنهاء الدالة، وبالتالي لن يُنفَّذ السطر الموجود خارج الحلقة، فإذا استخدمنا بدلًا من ذلك التعليمة <code>break</code>، فسيُنفّذ السطر fmt.Println()<code>‎</code> الأخير من المثال السابق.
</p>

<p>
	نعيد التذكير أنَّ التعليمة <code>‎return‎</code> تنهي عمل الدالة وقد تعيد قيمةً إذا أعقبها تعبير وكان ذلك محدد في تعريف الدالة.
</p>

<h2>
	إعادة عدة قيم
</h2>

<p>
	يمكن للدوال أن تُعيد أكثر من قيمة، إذ سنجعل برنامج repeat.go يُعيد قيمتين بحيث تكون القيمة الأولى القيمة المُكررة والثانية خطأً في حال كانت قيمة المعامِل <code>reps</code> أصغر أو تساوي 0.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_31" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    val</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> repeat</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">val</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func repeat</span><span class="pun">(</span><span class="pln">word string</span><span class="pun">,</span><span class="pln"> reps </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> reps </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Errorf</span><span class="pun">(</span><span class="str">"invalid value of %d provided for reps. value must be greater than 0."</span><span class="pun">,</span><span class="pln"> reps</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    var value string
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> reps</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        value </span><span class="pun">=</span><span class="pln"> value </span><span class="pun">+</span><span class="pln"> word
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> value</span><span class="pun">,</span><span class="pln"> nil
</span><span class="pun">}</span></pre>

<p>
	تتحقق الدالة <code>repeat</code> بدايةً من أن الوسيط <code>reps</code> صالح، فأيّ قيمة أقل أو تساوي الصفر ستؤدي إلى خطأ. بما أننا مررنا القيمة 1- إلى <code>reps</code> فهذا سيؤدي إلى تحقق شرط حدوث خطأ، وبالتالي ستُعاد قيمتين الأولى هي سلسلة فارغة "" والثانية هي رسالة خطأ، وبالطبع يجب علينا إعادة قيمتين دومًا تبعًا للتعريف الذي وضعناه في ترويسة الدالة، إذ حددنا أنّ هناك قيمتان مُعادتان من الدالة؛ فالأولى هي سلسلة والثانية هي خطأ، ولهذا السبب أعدنا سلسلةً فارغةً في حال ظهور خطأ.
</p>

<p>
	نستدعي الدالة <code>repeat</code> بداخل الدالة <code>main</code> ونُسند القيم المُعادة إلى متغيرين هما <code>value</code> و <code>err</code>، وبما أنّ هناك احتمال لحدوث خطأ، فسنتحقق في الأسطر التالية من وجوده، وفي حال وجوده سنطبع رسالةً تشير إلى الخطأ وسنستخدِم التعليمة <code>return</code> للخروج من الدالة <code>main</code> والبرنامج، وبتنفيذ البرنامج سنحصل على ما يلي:
</p>

<pre class="ipsCode">invalid value of -1 provided for reps. value must be greater than 0.
</pre>

<p>
	<strong>ملاحظة</strong>: من السلوكيات الجيدة في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">البرمجة</a> إعادة قيمتان أو ثلاثة، بالإضافة إلى إعادة كل الأخطاء كآخر قيمة معادة من الدالة. تعلّمنا في هذا القسم كيف نجعل تعليمة <code>return</code> تُعيد أكثر من قيمة.
</p>

<h2>
	الدوال المرنة Variadic
</h2>

<p>
	الدالة المرنة Variadic هي دالة لا تقبل أي قيمة أو تقبل قيمةً واحدةً أو قيمتين أو أكثر على أساس وسيط واحد، والدوال المرنة ليست شائعة الاستخدام لكنها تجعل الشيفرة أنظف وأكثر قابليةً للقراءة، وأحد الأمثلة على هذا النوع من الدوال هو الدالة <code>Println</code> من الحزمة <code>fmt</code>:
</p>

<pre class="ipsCode">func Println(a ...interface{}) (n int, err error)
</pre>

<p>
	نسمي الدالة التي تتضمن مُعامِلًا مُلحقًا بثلاثة نقاط <code>...</code> كما في الشيفرة أعلاه بالدالة المرنة، إذ تشير النقاط الثلاث إلى أنّ هذا المعامِل يمكن أن يكون صفر قيمة أو قيمةً واحدةً أو قيمتين أو عدة قيم، وبالتالي تُعَدّ الدالة <code>fmt.Println</code> دالةً مرنةً لأنها تتضمن مُعامِلًا مرنًا يسمى <code>a</code>.
</p>

<p>
	سنستخدِم في المثال التالي الدالة المرنة السابقة وسنبيّن كيف أنه من الممكن أن نمرر لها عددًا غير مُحدد من الوسائط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_33" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"one"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"one"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"two"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"one"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"two"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"three"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما تُلاحظ فإننا نستدعيها أول مرة بدون تمرير أيّ وسيط ثم نستدعيها مع تمرير وسيط واحد هو السلسلة <code>one</code> ثم نستدعيها مع وسيطين ثم نستدعيها مع ثلاثة وسائط، ولننفذ البرنامج الآن:
</p>

<pre class="ipsCode">$ go run print.go
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">one
one two
one two three
</pre>

<p>
	لاحظ أنّ السطر الأول من الخرج فارغ لأننا استدعينا تعليمة الطباعة بدون تمرير أيّ متغير ثم السطر الثاني يحتوي على <code>one</code> لأن دالة الطباعة التي استدعيناها في المرة الثانية تتضمنها، ثم <code>one two</code> لأننا مررناهما إلى دالة الطباعة في المرة الثالثة، وأخيرًا السطر الأخير <code>one two three</code> لأننا مررنا هذه الكلمات إلى دالة الطباعة في الشيفرة السابقة.
</p>

<p>
	سنتحدّث الآن عن كيفية تعريف هذه الدوال بعد أن اطلعنا على كيفية استخدام الدوال المرنة.
</p>

<h2>
	تعريف الدوال المرنة
</h2>

<p>
	كما ذكرنا سابقًا فإن الدوال المرنة تُعرّف من خلال وضع ثلاث نقاط <code>...</code> بعد اسم أحد المعامِلات فيها، وفي المثال التالي سنعرّف دالةً نمرر لها أسماءً لكي تُحَييهم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_35" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sayHello</span><span class="pun">()</span><span class="pln">
    sayHello</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">)</span><span class="pln">
    sayHello</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func sayHello</span><span class="pun">(</span><span class="pln">names </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">:=</span><span class="pln"> range names </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Hello %s\n"</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتضمّن الدالة <code>sayHello</code> معامِلًا اسمه <code>names</code> من النوع <code>string</code>، وكما نلاحظ فإنه توجد ثلاث نقاط بعد اسمه، وبالتالي هو معامل مرن أي يقبل عدد غير مُحدد من الوسائط، وبالتالي تُعَدّ الدالة <code>sayHello</code> هي دالةً مرنةً.
</p>

<p>
	تُعامِل هذه الدالة المعامِل <code>names</code> على أنه شريحة من الأسماء، أي أنها تعامله على أساس شريحة من السلاسل النصية <code>string[]</code>، وبالتالي يمكننا التكرار عليه بحلقة <code>for</code> من خلال استخدام العامِل <code>range</code>.
</p>

<p>
	ستحصل عند تنفيذ هذه الشيفرة على ما يلي:
</p>

<pre class="ipsCode">Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie
</pre>

<p>
	لاحظ أنه في المرة الأولى التي استدعينا فيها الدالة <code>sayHello</code> لم يُطبع أيّ شيء، وذلك لأننا لم نمرر لها أيّ قيمة، أي عمليًّا هي شريحة فارغة، وبالتالي لا تتضمن أي قيمة ليُكرر عليها، والآن سنُعدّل الشيفرة السابقة بحيث تطبع عبارةً مُحددةً عندما لا تُمرّر أيّ قيمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_37" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sayHello</span><span class="pun">()</span><span class="pln">
    sayHello</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">)</span><span class="pln">
    sayHello</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func sayHello</span><span class="pun">(</span><span class="pln">names </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">names</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"nobody to greet"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">:=</span><span class="pln"> range names </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Hello %s\n"</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضفنا تعليمة <code>if</code> تتحقق مما إذا كانت الشريحة فارغةً وهذا يُكافئ أن يكون طولها 0، وفي هذه الحالة سنطبع <code>nobody to greet</code>:
</p>

<pre class="ipsCode">nobody to greet
Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie
</pre>

<p>
	يجعل استخدام الدوال والمتغيرات المرنة شيفرتك أكثر قابليةً للقراءة، وسنُنشئ الآن دالةً مرنةً تربط الكلمات اعتمادًا على رمز مُحدّد، لكن سنكتب أولًا دالةً ليست مرنة لنُبيّن الفرق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_39" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">})</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">})</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">})</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">del string</span><span class="pun">,</span><span class="pln"> values </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	مرّرنا هنا الفاصلة <code>,</code> إلى الدالة <code>join</code> لكي يُنجز الربط اعتمادًا عليها، ثم مرّرنا شريحةً من الكلمات لكي تُربط، فكان الخرج كما يلي:
</p>

<pre class="ipsCode">Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
</pre>

<p>
	لاحظ هنا أنّ تعريف شريحة في كل مرة نستدعي فيها هذه الدالة قد يكون مُملًا وأكثر صعوبةً في القراءة، لذا سنُعرّف الآن الشيفرة نفسها لكن مع دالة مرنة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_41" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">del string</span><span class="pun">,</span><span class="pln"> values </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	سنحصل عند تشغيل البرنامج على خرج المثال السابق نفسه:
</p>

<pre class="ipsCode">Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
</pre>

<p>
	يمكن بسهولة ملاحظة أنّ استخدام مفهوم الدالة المرنة قد جعل من الدالة <code>join</code> أكثر قابليةً للقراءة.
</p>

<h2>
	ترتيب الوسائط المرنة
</h2>

<p>
	يمكنك تعريف معامِل مرن واحدة فقط في الدالة ويجب أن يكون هو المعامِل الأخير في ترويسة الدالة، فإذا عرّفتَ أكثر من معامِل مرن أو وضعته قبل المعامِلات العادية، فسيظهر لك خطأ وقت التصريف compilation error.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_43" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">values </span><span class="pun">...</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> del string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	وضعنا هنا المعامِل المرن <code>values</code> أولًا ثم وضعنا المعامِل العادي <code>del</code>، وبالتالي خالفنا الشرط المذكور سلفًا، وبالتالي سنحصل على الخطأ التالي:
</p>

<pre class="ipsCode">./join_error.go:18:11: syntax error: cannot use ... with non-final parameter values
</pre>

<p>
	عند تعريف دالة مرنة لا يمكن أن يكون المعامِل الأخير إلا معاملًا مرنًا.
</p>

<h2>
	تفكيك الوسائط
</h2>

<p>
	رأينا كيف أنّ المعامل المرن سيسمح لنا بتمرير 0 قيمة أو قيمة واحدة أو أكثر من قيمة إلى الدالة، لكن هناك حالات سيكون لدينا فيها شريحة من القيم نريد تمريرها إلى الدالة المرنة، لذا دعونا نرى الدالة <code>join</code> التي بنيناها مؤخرًا لرؤية ما يحدث:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_45" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    names </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">}</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> names</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">del string</span><span class="pun">,</span><span class="pln"> values </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	سنحصل عند تشغيل البرنامج على خطأ وقت التصريف:
</p>

<pre class="ipsCode">./join-error.go:10:14: cannot use names (type []string) as type string in argument to join
</pre>

<p>
	على الرغم من أن الدالة المرنة ستحوّل المعامِل <code>values ...string</code> إلى شريحة من السلاسل النصية <code>string[]</code>، إلا أنّ هذا لا يعني أنه بإمكاننا تمرير شريحة من السلاسل على أساس وسيط، فالمُصرّف يتوقع وسائط منفصلةً من نوع سلسلة نصية.
</p>

<p>
	يمكننا لحل هذه المشكلة تفكيك قيم الشريحة -أي فصلها عمليًّا- من خلال وضع ثلاثة نقط بعد اسم الشريحة عندما نُمررها لدالة مرنة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_47" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    names </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">}</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> names</span><span class="pun">...)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">del string</span><span class="pun">,</span><span class="pln"> values </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	لاحظ أننا وضعنا 3 نقاط بعد اسم الشريحة <code>names</code> عندما مررناها إلى الدالة <code>join</code>، وهذا يؤدي إلى <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r824/" rel="">تفكيك</a> عناصر الشريحة، وبالتالي كأنها قيم منفصلة، وسيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Sammy,Jessica,Drew,Jamie
</pre>

<p>
	لاحظ أنه مازال بإمكاننا عدم تمرير أيّ شيء أو تمرير أيّ عدد نريده من القيم، ويبيّن المثال التالي كل الحالات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2729_49" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var line string

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">}...)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jessica"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

    line </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="str">","</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

func join</span><span class="pun">(</span><span class="pln">del string</span><span class="pun">,</span><span class="pln"> values </span><span class="pun">...</span><span class="pln">string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    var line string
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> v
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            line </span><span class="pun">=</span><span class="pln"> line </span><span class="pun">+</span><span class="pln"> del
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> line
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Sammy,Jessica,Drew,Jamie
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
</pre>

<p>
	أصبحنا الآن نعرف كيف نمرِّر 0 قيمة أو أكثر إلى دالة مرنة، كما أصبحنا نعرف كيف يمكننا تمرير شريحة إلى دالة مرنة.
</p>

<p>
	غالبًا ما تكون الدوال المرنة مفيدةً في الحالات التالية:
</p>

<ul>
	<li>
		عندما تكون بحاجة إلى تعريف شريحة مؤقتًا من أجل تمريرها إلى دالة.
	</li>
	<li>
		لجعل الشيفرة أكثر قابليةً للقراءة.
	</li>
	<li>
		عندما يكون عدد الوسائط غير معروف أو متغير مثل دالة الطباعة.
	</li>
</ul>

<h2>
	الخاتمة
</h2>

<p>
	تُعَدّ الدوال كتلًا من التعليمات البرمجية التي تُنفِّذ إجراءات معيّنة داخل البرنامج، كما تساعد على جعل الشفرة تركيبيةً وقابلةً لإعادة الاستخدام، بالإضافة إلى أنها تنظمها وتسهل من قراءتها، كما تجعل الدوال المرنة الشيفرة أكثر قابليةً للقراءة، إلا أنها ليست شائعة الاستخدام، ولتتعلم كيف تجعل برنامجك تركيبيًّا أكثر، فيمكنك قراءة مقال <a href="https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1903/" rel="">كيفية تعريف الحزم في لغة جو Go</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقالَين <a href="https://www.digitalocean.com/community/tutorials/how-to-define-and-call-functions-in-go" rel="external nofollow">How To Define and Call Functions in Go</a> وللمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-use-variadic-functions-in-go" rel="external nofollow">How To Use Variadic Functions in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1950/" rel="">التعامل مع حلقة التكرار For في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1962</guid><pubDate>Tue, 18 Apr 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x62D;&#x644;&#x642;&#x629; &#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631; For &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1950/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/---For----Go.png.42f8120403be8b100a8cd9f9cb77aeab.png" /></p>
<p>
	يسمح لنا استخدام حلقات التكرار في <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-r1956/" rel="">برمجة الحاسوب</a> بأتمتة وتكرار المهام المتشابهة مرات عدة ريثما يتحقق شرط معيّن أو ظهور حدث محدد، فتخيل إذا كان لديك قائمة بالملفات التي تحتاج إلى معالجتها أو إذا كنت تريد حساب عدد الأسطر في المقالة أو إدخال 10 أعداد أو أسماء من المُستخدِم، فيمكنك استخدام حلقة في التعليمات البرمجية الخاصة بك لحل هذه الأنواع من المشاكل.
</p>

<p>
	سنشرح في هذا المقال كيفية استخدام حلقة <code>for</code> في <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">لغة جو</a>، وهي الحلقة الوحيدة المتوفرة فيها على عكس اللغات الأخرى التي تتضمن عدة أنواع من الحلقات مثل حلقة <code>while</code> أو <code>do</code>، فالهدف من وجود نوع حلقة واحدة هو التبسيط وتجنب الارتباك بين المبرمجين من الأنواع المختلفة، إذ نكتفي بواحدة فقط بدلًا من وجود عدة أنواع للحلقات تحقق الغرض نفسه وبالتكلفة نفسها.
</p>

<p>
	تؤدي حلقة <code>for</code> إلى تكرار تنفيذ جزء من الشيفرات بناءً على عدّاد أو على <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">متغير</a>، وهذا يعني أنّ حلقات <code>for</code> تستعمل عندما يكون عدد مرات تنفيذ حلقة التكرار معلومًا قبل الدخول في الحلقة، لكن في حقيقة الأمر يمكنك استخدامها حتى إذا لم يكن عدد التكرارات معلومًا من خلال استخدام تعليمة <code>break</code> كما سترى لاحقًا.
</p>

<p>
	سنبدأ بالحديث في هذا المقال عن الأنواع المختلفة من هذه الحلقة ثم كيفية التكرار على أنواع البيانات التسلسلية مثل البيانات النصية Strings ثم الحلقات المتداخلة.
</p>

<h2>
	التصريح عن حلقة For
</h2>

<p>
	حددت لغة جو 3 طرق مختلفة لإنشاء الحلقات كُلٌّ منها بخصائص مختلفة بوضع كل حالات الاستخدام الممكنة للحلقات في الحسبان، وهي إنشاء حلقة for مع شرط Condition أو ForClause أو RangeClause، إذ سنشرح في هذا القسم كيفية تصريح واستخدام أنواع ForClause و Condition، لذا دعونا نلقي نظرةً على كيفية استخدام حلقة <code>for</code> مع ForClause أولًا.
</p>

<p>
	تُعرّف حلقة ForClause من خلال كتابة تعليمة التهيئة initial statement متبوعة بشرط Condition متبوعة بتعليمة التقدّم Post Statement:
</p>

<pre class="ipsCode">for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
    [Action]
}
</pre>

<p>
	لكي نفهم المكونات السابق سنرى المثال التالي الذي يعرض حلقة <code>for</code> تتزايد ضمن نطاق محدد من القيم باستخدام التعريف السابق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_9" style=""><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتمثل الجزء الأول من الحلقة في تعليمة التهيئة <code>i := 0</code> والتي تعبر عن تصريح متغير اسمه <code>i</code> يُسمى متغير الحلقة وقيمته الأولية هي 0؛ أما الجزء الثاني فهو الشرط <code>i &lt; 5</code> والذي يُمثّل الشرط الذي يجب أن يتحقق لكي ندخل في الحلقة أو في التكرار التالي من الحلقة، إذ يمكن القول ادخُل في الحلقة ونفّذ محتواها طالما أنّ قيمة <code>i</code> أصغر من 5، والجزء الأخير هو تعليمة التقدّم <code>++i</code> والتي تشير إلى التعديل الذي سنجريه على متغير الحلقة <code>i</code> بعد انتهاء كل تكرار، إذ يكون التعديل هنا هو زيادته بمقدار واحد.
</p>

<p>
	سيكون خرج البرنامج كما يلي:
</p>

<pre class="ipsCode">0
1
2
3
4
</pre>

<p>
	تتكرر الحلقة 5 مرات، بدايةً تكون قيمة <code>i</code> تساوي 0 وهي أصغر من 5، لذا ندخل في الحلقة وننفّذ محتواها <code>(fmt.Println(i</code> ثم نزيد قيمة متغير الحلقة بواحد فتصبح قيمته 1 وهي أصغر من 5، ثم ننفّذ محتوى الحلقة مرةً أخرى ونزيدها بواحد فتصبح 2 وهي أصغر من 5 وهكذا إلى أن تصبح قيمة متغير الحلقة 5 فينتهي تنفيذ الحلقة.
</p>

<p>
	<strong>ملاحظة</strong>: تبدأ الفهرسة بالقيمة 0، لذا ستكون قيمة <code>i</code> في المرة الخامسة للتنفيذ هي 4 وليس 5.
</p>

<p>
	طبعًا ليس بالضرورة أن تبدأ بقيمة محددة مثل الصفر أو تنتهي بقيمة محددة وإنما يمكنك تحديد أي نطاق تريده كما في هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_11" style=""><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنبدأ هنا بالقيمة الأولية 20 وننتهي عند الوصول إلى القيمة 25 بحيث تكون أقل تمامًا من 25، أي ننتهي بالعدد 24:
</p>

<pre class="ipsCode">20
21
22
23
24
</pre>

<p>
	يمكنك أيضًا التحكم بخطوات الحلقة على عداد الحلقة كما تريد، إذ يمكنك مثلًا تقديم قيمة المتغير بثلاثة بعد كل تكرار كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_13" style=""><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">15</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نبدأ هنا بالعدد 0 وننتهي عند الوصول إلى 15، وبعد كل تكرار نزيد العدّاد (متغير الحلقة) بثلاثة، وسيكون الخرج كما يلي:
</p>

<pre class="ipsCode">0
3
6
9
12
</pre>

<p>
	يمكننا أيضًا التكرار بصورة عكسية، أي البدء بقيمة كبيرة والعودة خلفًا، إذ سنبدأ في المثال التالي بالعدد 100 وننتهي عند الوصول إلى 0، وهنا لابد من أن يكون التقدم عكسيًا، أي باستخدام عملية الطرح وليس الجمع:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_15" style=""><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وضعنا هنا القيمة الأولية على 100 ووضعنا شرطًا للتوقف <code>i &lt; 0</code> عند الصفر وجعلنا التقدم عكسيًا بمقدار 10 إلى الخلف بحيث سينقص 10 من قيمة متغير الحلقة بعد كل تكرار، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">100
90
80
70
60
50
40
30
20
10
</pre>

<p>
	يمكنك أيضًا الاستغناء عن كتابة القيمة الأولية للمتغير وعن مقدار التقدّم وترك الشرط فقط، إذ نسمي هذا النوع من الحلقات بحلقة الشرط Condition loop والتي تكافئ الحلقة while في لغات البرمجة الأخرى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_17" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
    i</span><span class="pun">++</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	صرّحنا هنا عن المتغير <code>i</code> قبل الدخول إلى الحلقة، إذ يُنفّذ ما بداخل الحلقة طالما أنّ الشرط محقق، أي <code>i</code> أصغر من 5، ولاحظ أيضًا أننا نزيد من قيمة المتغير <code>i</code> في نهاية الكتلة البرمجية الخاصة بالحلقة، فذا لم نزده، فسندخل في حلقة لانهائية، وفي الواقع نحن لم نستغنِ عن تعليمة التهيئة أو التقدّم (الخطوات)، وإنما عرّفناهم بطريقة مختلفة، والغاية من هذا التعريف هو المطابقة مع <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-while-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r509/" rel="">حلقة while</a> المستخدَمة في باقي اللغات.
</p>

<p>
	ذكرنا التعليمة <code>break</code> في بداية المقال والتي سنستخدِمها عندما يكون شرط التوقف غير مرتبط بعدد محدد من التكرارات وإنما بحدث ما مثل تكرار عملية إدخال كلمة المرور من المستخدِم طالما ليست صحيحةً، ويمكن التعبير عن هكذا حلقة من خلال كتابة <code>for</code> فقط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_19" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> someCondition </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">break</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="com">// do action here</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مثال آخر على ذلك عندما نقرأ من بنية غير محددة الحجم مثل المخزِّن المؤقت buffer ولا نعرف متى سننتهي من القراءة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_21" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"bytes"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"io"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    buf </span><span class="pun">:=</span><span class="pln"> bytes</span><span class="pun">.</span><span class="typ">NewBufferString</span><span class="pun">(</span><span class="str">"one\ntwo\nthree\nfour\n"</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        line</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> buf</span><span class="pun">.</span><span class="typ">ReadString</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">==</span><span class="pln"> io</span><span class="pun">.</span><span class="pln">EOF </span><span class="pun">{</span><span class="pln">

                fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
                </span><span class="kwd">break</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُصرّح في السطر <code>("buf :=bytes.NewBufferString("one\ntwo\nthree\nfour\n</code> عن مخزِّن مؤقت مع بعض البيانات، ونظرًا لأننا لا نعرف متى سينتهي المخزِّن المؤقت من القراءة، سننشئ حلقة <code>for</code> بدون أيّ بند، أي بدون شرط أو قيمة أولية أو مقدار تقدّم.
</p>

<p>
	نستخدِم داخل الحلقة <code>('line, err := buf.ReadString('\n</code> لقراءة سطر من المخزِّن المؤقت والتحقق مما إذا كان هناك خطأ في القراءة منه، فإذا كان هناك خطأ، فسنعالج الخطأ ونستخدِم الكلمة المفتاحية <code>break</code> للخروج من حلقة <code>for</code>، فكما نلاحظ أننا من خلال تعليمة <code>break</code> لم نعُد بحاجة إلى كتابة بند الشرط لإيقافها.
</p>

<p>
	تعلمنا في هذا المثال كيفية التصريح عن حلقة ForClause وكيفية استخدامها للتكرار على مجال محدد من القيم، كما تعلمنا أيضًا كيفية استخدام حلقة الشرط للتكرار حتى يتحقق شرط معيّن.
</p>

<h2>
	التكرار على أنواع البيانات المتسلسلة باستخدام RangeClause
</h2>

<p>
	من الشائع في جو استخدام الحلقات للتكرار على عناصر <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1791/" rel="">أنواع البيانات</a> المتسلسلة أو التجميعية مثل <a href="https://academy.hsoub.com/programming/go/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-go-r840/" rel="">الشرائح والمصفوفات</a> والسلاسل النصية، ولتسهيل هذه العملية يمكننا استخدام حلقة <code>for</code> مع بنية RangeClause، ويمكنك عمومًا استخدام بنية ForClause للتكرار على أيّ نوع من البيانات بطرق محددة طبعًا، إلا أن بنية RangeClause تُعَدّ مُنظّمَةً أكثر وأسهل في القراءة.
</p>

<p>
	بدايةً سنلقي نظرةً على كيفية التكرار باستخدام ForClause في هكذا حالات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_23" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sharks </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"hammerhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"great white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dogfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frilled"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bullhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"requiem"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sharks</span><span class="pun">);</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sharks</span><span class="pun">[</span><span class="pln">i</span><span class="pun">])</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بتشغيل الشيفرة السابقة سنحصل على الخرج التالي:
</p>

<pre class="ipsCode">hammerhead
great white
dogfish
frilled
bullhead
requiem
</pre>

<p>
	سنستخدِم الآن بنية RangeClause لتنفيذ الإجراءات نفسها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_25" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sharks </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"hammerhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"great white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dogfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frilled"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bullhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"requiem"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> shark </span><span class="pun">:=</span><span class="pln"> range sharks </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> shark</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيُطبع في هذه الحالة كل عنصر في القائمة. هنا استخدمنا المتغيرين <code>i</code> و <code>shark</code> من أجل عملية التكرار ويمكنك استخدام أيّ اسم آخر لهذه المتغيرات، إذ تعيد الكلمة المفتاحية <code>range</code> قيمتين؛ الأولى هي فهرس العنصر والثانية هي قيمته، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem
</pre>

<p>
	قد لا نكون بحاجة إلى عرض فهرس العنصر في بعض الأحيان، لكن إذا حذفناها، فسنتلقى خطأً في وقت التصريف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_27" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sharks </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"hammerhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"great white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dogfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frilled"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bullhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"requiem"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> shark </span><span class="pun">:=</span><span class="pln"> range sharks </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">shark</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">src/range-error.go:8:6: i declared and not used
</pre>

<p>
	نظرًا لأنّ <code>i</code> قد صُرِّح عنه في الحلقة <code>for</code>، ولكن لم يُستخدم مطلقًا، فسوف يُعطي المُصرّف <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/" rel="">خطأً</a> يُشير إلى أن هناك متغيرًا قد صُرّح عنه ولم يُستخدَم، وهذا الخطأ ستتلقاه في جو في أيّ وقت تُصرّح فيه عن متغير ولا تستخدِمه، ولحل هذه المشكلة سنستخدِم المتغير المجهول الذي يُعبَّر عنه بالشرطة السفلية <code>_</code> والذي يشير إلى أنّ هناك قيمة ستُعاد ونعرف ذلك لكن لا نريدها، لذا سنستبدل المتغير <code>i</code> بالمتغير المجهول وسينجح الأمر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_29" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sharks </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"hammerhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"great white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dogfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frilled"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bullhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"requiem"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> shark </span><span class="pun">:=</span><span class="pln"> range sharks </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">shark</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">hammerhead
great white
dogfish
frilled
bullhead
requiem
</pre>

<p>
	يوضِّح الخرج أنّ حلقة <code>for</code> قد تكررت على شريحة السلاسل وطُبع كل عنصر من الشريحة بدون الفهرس.
</p>

<p>
	يمكنك أيضًا استخدام الكلمة <code>range</code> لإضافة عناصر إلى قائمة ما:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_31" style=""><span class="pln">package main
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">
func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sharks </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"hammerhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"great white"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"dogfish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"frilled"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bullhead"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"requiem"</span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> range sharks </span><span class="pun">{</span><span class="pln">
        sharks </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">sharks</span><span class="pun">,</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> sharks</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']
</pre>

<p>
	أضفنا هنا السلسة 'shark' إلى الشريحة <code>sharks</code> عدة مرات من خلال التكرار عليها، أي أضفنا إليها x مرة، بحيث تكون x هي طول القائمة التي نُكرر عليها، ولاحظ هنا أننا لسنا بحاجة إلى استخدام المتغير المجهول <code>_</code> إطلاقًا، وذلك لأن هكذا حالة مُعرّفة ضمن جو، كما أننا لم نستخدِم أيّ متغير.
</p>

<p>
	يمكننا أيضًا استخدام العامِل <code>range</code> لملء قيم الشريحة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_33" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    integers </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="typ">int</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">integers</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> range integers </span><span class="pun">{</span><span class="pln">
        integers</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">integers</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نُصرِّح هنا عن الشريحة <code>integers</code> على أنها شريحة من الأعداد الصحيحة <code>int</code> ونحجز مساحةً لعشرة عناصر مُسبقًا ثم نطبع الشريحة ثم نملأ هذه الشريحة بقيم عناصر فهارسها، ثم نطبعها من جديد:
</p>

<pre class="ipsCode">[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]
</pre>

<p>
	نلاحظ أنه في المرة الأولى للطباعة تكون عناصر الشريحة صفرية، ﻷننا حجزنا 10 عناصر ولم نُعطهم قيمًا، أي القيمة الافتراضية هي 0، لكن في المرة التالية تكون قيم الشريحة من 0 إلى 9 وهذا يُكافئ قيم الفهارس لها.
</p>

<p>
	يمكننا أيضًا استخدام العامِل <code>range</code> للتكرار على محارف سلسلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_35" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sammy </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> letter </span><span class="pun">:=</span><span class="pln"> range sammy </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%c\n"</span><span class="pun">,</span><span class="pln"> letter</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">S
a
m
m
y
</pre>

<p>
	عند استخدام <code>range</code> للتكرار على عناصر <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/" rel="">رابطة map</a>، فستُعاد قيمة كل من المفتاح والقيمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_37" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    sammyShark </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"location"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ocean"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">:=</span><span class="pln"> range sammyShark </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">key </span><span class="pun">+</span><span class="pln"> </span><span class="str">": "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">color: blue
location: ocean
name: Sammy
animal: shark
</pre>

<p>
	<strong>ملاحظة</strong>: عناصر الرابطة غير مُرتبة، وبالتالي ستُطبع عناصرها بترتيب عشوائي في كل مرة تُنفّذ فيها الشيفرة.
</p>

<p>
	الآن بعد أن تعرّفنا على كيفية التكرار على العناصر المتسلسة، سنتعلم كيفية استخدام الحلقات المتداخلة.
</p>

<h2>
	الحلقات المتداخلة Nested Loops
</h2>

<p>
	يمكن لحلقات التكرار في جو أن تداخل كما هو الحال في بقية لغات البرمجة، فحلقة التكرار المتداخلة هي الحلقة الموجودة ضمن حلقة تكرار أخرى وهذا مفيد لتكرار عدة عمليات على كل عنصر مثلًا وهي شبيهة <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">بتعليمات if</a> المتداخلة، وتُبنى حلقات التكرار المتداخلة كما يلي:
</p>

<pre class="ipsCode">for {
    [Action]
    for {
        [Action]  
    }
}
</pre>

<p>
	يبدأ البرنامج بتنفيذ حلقة التكرار الخارجية ويُنفَّذ أول تكرار فيها والذي سيؤدي إلى الدخول إلى حلقة التكرار الداخلية، مما يؤدي إلى تنفيذها إلى أن تنتهي تمامًا، بعد ذلك سيعود تنفيذ البرنامج إلى بداية حلقة التكرار الخارجية، ويبدأ بتنفيذ التكرار الثاني ثم سيصل التنفيذ إلى حلقة التكرار الداخلية، وستُنفَّذ حلقة التكرار الداخلية بالكامل، ثم سيعود التنفيذ إلى بداية حلقة التكرار الخارجية، وهكذا إلى أن ينتهي تنفيذ حلقة التكرار الخارجية أو إيقاف حلقة التكرار عبر استخدام break أو غيرها من التعليمات.
</p>

<p>
	لنُنشِئ مثالًا يستعمل حلقة <code>for</code> متداخلة لكي نفهم كيف تعمل بدقة، حيث ستمر حلقة التكرار الخارجية في المثال الآتي على شريحة من الأعداد اسمها <code>numList</code>؛ أما حلقة التكرار الداخلية فستمر على شريحة من السلاسل النصية اسمها <code>alphaList</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_39" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    numList </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">}</span><span class="pln">
    alphaList </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"a"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"b"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"c"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> range numList </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> letter </span><span class="pun">:=</span><span class="pln"> range alphaList </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">letter</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيظهر الناتج التالي عند تشغيل البرنامج:
</p>

<pre class="ipsCode">1
a
b
c
2
a
b
c
3
a
b
c
</pre>

<p>
	يُظهِر الناتج السابق أنَّ البرنامج قد أكمل أول تكرار على عناصر حلقة التكرار الخارجية بطباعة العدد، ومن ثم بدأ بتنفيذ حلقة التكرار الداخلية، لذا طبع المحارف a و b و c على التوالي، وبعد انتهاء تنفيذ حلقة التكرار الداخلية، عاد البرنامج إلى بداية حلقة التكرار الخارجية طابعًا العدد 2، ثم بدأ تنفيذ حلقة التكرار الداخلية، مما يؤدي إلى إظهار a و b و c مجددًا وهكذا.
</p>

<p>
	يمكن الاستفادة من حلقات <code>for</code> المتداخلة عند المرور على عناصر شريحة تتألف من شرائح، فإذا استعملنا حلقة تكرار وحيدة لعرض عناصر شريحة تتألف من عناصر تحتوي على شرائح، فستُعرَض قيم الشرائح الداخلية على أساس عنصر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_41" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ints </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[][]</span><span class="typ">int</span><span class="pun">{</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">},</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">3</span><span class="pun">},</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> range ints </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">[0 1 2]
[-1 -2 -3]
[9 8 7]
</pre>

<p>
	إذا أردنا الوصول إلى العناصر الموجودة في الشرائح الداخلية، فيمكننا استعمال حلقة <code>for</code> متداخلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_43" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ints </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[][]</span><span class="typ">int</span><span class="pun">{</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">},</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">3</span><span class="pun">},</span><span class="pln">
        </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> range ints </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> j </span><span class="pun">:=</span><span class="pln"> range i </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">j</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">0
1
2
-1
-2
-3
9
8
7
</pre>

<p>
	نستطيع الاستفادة من حلقات <code>for</code> المتداخلة عندما نريد التكرار على عناصر قابلة للتكرار داخل الشرائح.
</p>

<h2>
	استخدام تعليمات continue و break
</h2>

<p>
	تسمح لك حلقة <code>for</code> بأتمتة وتكرار المهام بطريقة فعّالة، لكن في بعض الأحيان قد يتدخل عامل خارجي في طريقة تشغيل برنامجك، وعندما يحدث ذلك، فربما تريد من برنامجك الخروج تمامًا من حلقة التكرار أو تجاوز جزء من الحلقة قبل إكمال تنفيذها أو تجاهل هذا العامِل الخارجي تمامًا، لذا يمكنك فعل ما سبق باستخدام تعابير <code>break</code> و <code>continue</code>.
</p>

<h3>
	تعليمة break
</h3>

<p>
	توفِّر لك تعليمة <code>break</code> -والتي تعاملنا معها سابقًا- القدرة على الخروج من حلقة التكرار عند حدوث عامل خارجي، وتوضَع عادةً ضمن تعبير <code>if</code>، وفيما يلي أحد الأمثلة الذي يستعمل تعليمة <code>break</code> داخل حلقة <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_45" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">==</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Breaking out of loop"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> </span><span class="com">// break here</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"The value of i is"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Exiting program"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بنينا حلقة تكرار <code>for</code> التي تعمل طالما كانت قيمة المتغير <code>i</code> أصغر من 10 وحددنا التقدّم بمقدار 1 بعد كل تكرار، ثم لدينا تعليمة <code>if</code> التي تختبر فيما إذا كان المتغير <code>i</code> مساوٍ للعدد 5، فعند حدوث ذلك، فستُنفَّذ <code>break</code> للخروج من الحلقة.
</p>

<p>
	توجد داخل حلقة التكرار الدالة <code>fmt.Println()‎</code> التي تُنفَّذ في كل تكرار وتطبع قيمة المتغير <code>i</code> إلى أن نخرج من الحلقة عبر <code>break</code> وهنا يكون لدينا تعليمة طباعة أخرى تطبع Breaking out of loop، ولكي نتأكد أننا خرجنا من الحلقة تركنا تعليمة طباعة أخرى تطبع Exiting program، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">The value of i is 0
The value of i is 1
The value of i is 2
The value of i is 3
The value of i is 4
Breaking out of loop
Exiting program
</pre>

<p>
	يُظهر الناتج السابق أنَّه بمجرد أن أصبحت قيمة المتغير <code>i</code> مساويةً للعدد 5، فسينتهي تنفيذ حلقة التكرار عبر <code>break</code>.
</p>

<h3>
	تعليمة continue
</h3>

<p>
	تعليمة <code>continue</code> تسمح لنا بتخطي جزء من حلقة التكرار عند حدوث عامِل خارجي مع إكمال بقية الحلقة إلى نهايتها، أي سينتقل تنفيذ البرنامج إلى أوّل حلقة التكرار عند تنفيذ <code>continue</code>، وتوضَع عادةً ضمن تعليمة <code>if</code>.
</p>

<p>
	سنستخدِم البرنامج نفسه الذي استعملناه لشرح التعبير <code>break</code> أعلاه، لكننا سنستخدم التعبير <code>continue</code> بدلًا من <code>break</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_47" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">==</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Continuing loop"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln"> </span><span class="com">// break here</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"The value of i is"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Exiting program"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الفرق الوحيد عن الشيفرة السابقة هي أننا استبدلنا <code>break</code> بتعليمة <code>continue</code>، وبالتالي لن يتوقف البرنامج عند وصول متغير الحلقة إلى 5، وإنما فقط سيتخطاها ويتابع التنفيذ، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">The value of i is 0
The value of i is 1
The value of i is 2
The value of i is 3
The value of i is 4
Continuing loop
The value of i is 6
The value of i is 7
The value of i is 8
The value of i is 9
Exiting program
</pre>

<p>
	نلاحظ أنَّ السطر الذي يجب أن يحتوي على <code>The value of i is 5</code> ليس موجودًا في المخرجات، لكن سيُكمَل تنفيذ حلقة التكرار بعد هذه المرحلة مما يؤدي إلى طباعة الأعداد من 6 إلى 10 قبل إنهاء تنفيذ الحلقة.
</p>

<p>
	يمكنك استخدام التعليمة <code>continue</code> لتفادي استخدام تعابير شرطية معقدة ومتداخلة أو لتحسين أداء البرنامج عن طريق تجاهل الحالات التي ستُرفَض نتائجها، وبالتالي ستؤدي تعليمة <code>continue</code> إلى جعل البرنامج يتجاهل تنفيذ حلقة التكرار عند تحقيق شرط معيّن، لكن بعد ذلك سيُكمِل تنفيذ الحلقة مثل العادة.
</p>

<h2>
	تعليمة break مع الحلقات المتداخلة
</h2>

<p>
	من المهم أن تتذكر أنّ تعليمة <code>break</code> ستوقف فقط تنفيذ الحلقة الداخلية التي يتم استدعاؤها فيها، فإذا كان لديك مجموعة متداخلة من الحلقات، فستحتاج إلى تعليمة <code>break</code> لكل حلقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8103_49" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> outer </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> outer </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> outer</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> outer </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Breaking out of outer loop"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> </span><span class="com">// break تعليمة</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"The value of outer is"</span><span class="pun">,</span><span class="pln"> outer</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> inner </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> inner </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> inner</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> inner </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Breaking out of inner loop"</span><span class="pun">)</span><span class="pln">
                </span><span class="kwd">break</span><span class="pln"> </span><span class="com">// break تعليمة</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"The value of inner is"</span><span class="pun">,</span><span class="pln"> inner</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Exiting program"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتكرر الحلقتان 5 مرات ولكل منهما تعليمة <code>if</code> مع تعليمة <code>break</code>، فالحلقة الخارجية سوف تنكسر أو تُنهى -أي يُطبّق عليها <code>break</code>- إذا كانت قيمة المتغير <code>outer</code> تساوي 3؛ أما الحلقة الداخلية فستنكسر إذا كانت قيمة المتغير <code>inner</code> تساوي 2، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">The value of outer is 0
The value of inner is 0
The value of inner is 1
Breaking out of inner loop
The value of outer is 1
The value of inner is 0
The value of inner is 1
Breaking out of inner loop
The value of outer is 2
The value of inner is 0
The value of inner is 1
Breaking out of inner loop
Breaking out of outer loop
Exiting program
</pre>

<p>
	لاحظ أنه في كل مرة تنكسر فيها الحلقة الداخلية، فإن الحلقة الخارجية لا تنكسر لأن تعليمة <code>break</code> ستكسِر فقط تنفيذ الحلقة الداخلية التي استُدعيَت منها.
</p>

<h2>
	الخاتمة
</h2>

<p>
	رأينا في هذا المقال كيف تعمل حلقة التكرار <code>for</code> في لغة جو وكيف نستطيع إنشاءها واستعمالها، حيث تستمر حلقة for بتنفيذ مجموعة من الشيفرات لعدد محدد من المرات، كما تعرّفنا أيضًا على ثلاثة أنواع مختلفة من هذه الحلقة وكيفية استخدام كل منها، وتعلمنا أيضًا كيفية استخدام تعليمتَي <code>continue</code> و <code>break</code> للتحكم باستخدام حلقة for بفاعلية أكبر.
</p>

<p>
	ترجمة -وبتصرُّف- للمقالَين <a href="https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go" rel="external nofollow">How To Construct For Loops in Go</a> و <a href="https://www.digitalocean.com/community/tutorials/using-break-and-continue-statements-when-working-with-loops-in-go" rel="external nofollow">Using Break and Continue Statements When Working with Loops in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%A8%D8%AF%D9%8A%D9%84-switch-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1949/" rel="">التعامل مع تعليمة التبديل Switch في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1950</guid><pubDate>Wed, 12 Apr 2023 15:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x62A;&#x639;&#x644;&#x64A;&#x645;&#x629; &#x627;&#x644;&#x62A;&#x628;&#x62F;&#x64A;&#x644; Switch &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%A8%D8%AF%D9%8A%D9%84-switch-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1949/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/----Switch----Go.png.7a07dc8f789e7b8d16c770a2f4a915af.png" /></p>
<p>
	تمنح التعليمات الشرطية المبرمجين القدرة على التحكم بسير عمل برامجهم وتفريعها وتوجيهها لاتخاذ بعض الإجراءات إذا كان الشرط المحدَّد صحيحًا وإجراء آخر إذا كان الشرط خاطئًا.
</p>

<p>
	تتوفَّر عدة تعليمات للتفريع branching statements بلغة جو، فقد تناولنا تعليمة <code>if</code> و <code>else</code> و <code>else if</code> والتعليمات الشرطية المتداخلة في المقال السابق <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">كيفية كتابة التعليمات الشرطية if في لغة جو Go</a>، وسننتقل الآن إلى تعليمة تفريع أخرى تدعى <code>switch</code> والتي يُعدّ استخدامها أقل شيوعًا من التعليمات السابقة، ولكن مع ذلك فهي مفيدة أحيانًا للتعبير عن نوع معيّن من التفريع المُتعدِّد multiway branches عندما نريد مثلًا مقارنة قيمة متغير (أو دخل من المستخدِم) بعدة قيم محتملة واتخاذ إجراء محدد بناءً على ذلك.
</p>

<p>
	إن أفضل مثال عملي على ذلك هو برنامج الآلة الحاسبة الذي يُجد ناتج عملية حسابية لعددين، بحيث يكون الدخل هو عملية حسابية -وهذا يكافئ عدة قيم محتملة + أو - أو * أو /- وعددين x و y.، وسيعتمد هنا الإجراء المُتخذ على نوع العملية التي يُدخلها المستخدِم، فإذا أدخل + فسيكون الإجراء x+y، وإذا أدخل - فسيكون x-y، وهكذا.
</p>

<p>
	يمكن تحقيق التفريع المتعدد باستخدام <a href="https://academy.hsoub.com/programming/python/%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1892/" rel="">التعليمات الشرطية</a> التي تعرفنا عليها في <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">المقال السابق</a>، لكن يمكن تحقيقه أيضًا باستخدام تعليمة <code>switch</code> كما سنرى في هذا المقال.
</p>

<h2>
	بنية التعليمة Switch
</h2>

<p>
	عادةً ما تُستخدَم تعليمة التبديل Switch لوصف الحالات التي يكون لدينا فيها عدة إجراءات ممكنة تبعًا لقيم متغير أو عدة متغيرات مُحتمَلة، ويوضح المثال التالي كيف يمكننا تحقيق ذلك باستخدام <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">تعليمات if</a>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1401_10" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    flavors </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"chocolate"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"banana"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> flav </span><span class="pun">:=</span><span class="pln"> range flavors </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> flav </span><span class="pun">==</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is my favorite!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> flav </span><span class="pun">==</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is great!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> flav </span><span class="pun">==</span><span class="pln"> </span><span class="str">"chocolate"</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is great!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"I've never tried"</span><span class="pun">,</span><span class="pln"> flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"before"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">chocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
</pre>

<p>
	نُعرّف بداخل الدالة <code>main</code> شريحةً slice من نكهات المثلجات ثم نستخدِم <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1950/" rel="">حلقة for للتكرار</a> على عناصرها ثم نستخدِم ثلاث تعليمات <code>if</code> لطباعة رسائل مختلفة تشير إلى تفضيلات نكهات المثلجات المختلفة، إذ يجب على كل تعليمة <code>if</code> أن تتضمن تعليمة <code>Continue</code> لإيقاف التكرار الحالي في الحلقة لكي لا تُطبَع الرسالة الافتراضية في نهاية كتلة الحلقة.
</p>

<p>
	لاحظ أنه كلما أضفنا نكهةً جديدةً إلى الشريحة السابقة، فسيتعين علينا إضافة التفضيل المقابل لها، وبالتالي الاستمرار في كتابة تعليمات <code>if</code> في كل مرة نضيف فيها عنصرًا جديدًا إلى الشريحة، كما يجب أيضًا تكرار تعليمات <code>if</code> مع الرسائل المكررة كما في حالة "Vanilla" و "chocolate".
</p>

<p>
	كما ترى فإن تكرار تعليمات <code>if</code> باستمرار ووجود رسالة افتراضية في نهاية كتلة الحلقة بدون تعليمة <code>if</code> يجعل الأمر غريبًا وغير مرتب تمامًا، ولاحظ أيضًا أنّ كل ما يحدث هو مقارنة المتغير بقيم متعددة واتخاذ إجراءات مختلفة بناءً على ذلك، وهنا تكون بنية Switch قادرةً على التعبير عمّا يحدث بطريقة أفضل وأكثر تنظيمًا ورتابةً.
</p>

<p>
	تبدأ تعليمة التبديل بالكلمة المفتاحية <code>switch</code> متبوعةً بمتغير أو عدة متغيرات لإجراء مقارنات على أساسها (أبسط شكل) متبوعةً بقوسين معقوصَين توضَع ضمنها الحالات المتعددة التي يمكن أن يحملها المتغير أو المتغيرات، وكل من هذه الحالات تبدأ بالكلمة المفتاحية <code>case</code> متبوعةً بقيمة محتملة للمتغير، بحيث تقابل كل حالة إجراءً مُحددًا يُنفَّذ في حال كانت قيمة المتغير تطابق القيمة المحتملة، وسيبدو الأمر أوضح في المثال التالي الذي يكافئ المثال السابق تمامًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1401_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    flavors </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"chocolate"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"banana"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> flav </span><span class="pun">:=</span><span class="pln"> range flavors </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">switch</span><span class="pln"> flav </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is my favorite!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"chocolate"</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is great!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"I've never tried"</span><span class="pun">,</span><span class="pln"> flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"before"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">chocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
</pre>

<p>
	نُعرّف بداخل الدالة <code>main</code> كما في المرة السابقة شريحةً slice من نكهات المثلجات ثم نستخدِم حلقة <code>for</code> للتكرار على عناصرها، لكن سنستخدِم في هذه المرة تعليمة التبديل وسنلغي استخدام التعليمة <code>if</code>، إذ وضعنا المتغير <code>flav</code> بعد الكلمة <code>switch</code> وستُختبر قيمة هذا المتغير وستُنفّذ إجراءات محددة بناءً عليها:
</p>

<ul>
	<li>
		الحالة الأولى سيطبع رسالةً محددةً عندما تكون قيمة هذا المتغير تساوي strawberry.
	</li>
	<li>
		الحالة الثانية سيطبع رسالةً محددةً عندما تكون قيمة هذا المتغير تساوي vanilla أو chocolate، ولاحظ أنه في المثال السابق اضطررنا لكتابة تعليمتَي <code>if</code>.
	</li>
	<li>
		الحالة الأخيرة هي الحالة الافتراضية وتسمى <code>default</code> حيث أنه إذا لم تتحقق أيّ من الحالات السابقة، فستُنفّذ هذه التعليمة ويطبع الرسالة المحددة، لكن إذا تحققت حالة ما من الحالات السابقة، فلن تُنفّذ هذه التعليمة إطلاقًا.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: لم نحتاج إلى استخدام <code>continue</code> لأن تعليمة التبديل لا تُنفّذ إلا حالةً واحدةً فقط تلقائيًا.
</p>

<p>
	يعرض هذا المثال الاستخدام الأكثر شيوعًا لتعليمة التبديل وهو مقارنة قيمة متغير بعدة قيم محتملة، إذ توفِّر لنا تعليمة التبديل الراحة عندما نريد اتخاذ الإجراء نفسه لعدة قيم مختلفة وتنفيذ إجراءات محددة عندما لا تُستوفَى أيّ من شروط الحالات المُعرَّفة.
</p>

<h2>
	تعليمات التبديل العامة
</h2>

<p>
	تُعَدّ تعليمة التبديل مفيدةً في تجميع مجموعات من الشروط الأكثر تعقيدًا لإظهار أنها مرتبطة بطريقة ما، وغالبًا ما يُستخدَم ذلك عند مقارنة متغير أو عدة متغيرات بمجال من القيم بدلًا من القيم المحددة كما في المثال السابق، ويُعَدّ المثال التالي تحقيقًا للعبة تخمين باستخدام تعليمات <code>if</code> التي يمكن أن تستفيد من تعليمة التبديل كما رأينا سابقًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1401_14" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"math/rand"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    rand</span><span class="pun">.</span><span class="typ">Seed</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">UnixNano</span><span class="pun">())</span><span class="pln">
    target </span><span class="pun">:=</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        var guess </span><span class="typ">int</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="str">"Enter a guess: "</span><span class="pun">)</span><span class="pln">
        _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">guess</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Invalid guess: err:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> guess </span><span class="pun">&gt;</span><span class="pln"> target </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Too high!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> guess </span><span class="pun">&lt;</span><span class="pln"> target </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Too low!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"You win!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">break</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيختلف الخرج بناءً على العدد العشوائي المحدد ومدى جودة لعبك، وفيما يلي ناتج دورة لعب واحدة:
</p>

<pre class="ipsCode">Enter a guess: 10
Too low!
Enter a guess: 15
Too low!
Enter a guess: 18
Too high!
Enter a guess: 17
You win!
</pre>

<p>
	تحتاج لعبة التخمين إلى عدد عشوائي لمقارنة التخمينات به، لذا سنستخدِم الدالة <code>rand.Intn</code> من<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/" rel=""> الحزمة</a> <code>math/rand</code> لتوليده، كما سنستخدِم <code>rand.Seed</code> مولّد الأعداد العشوائية بناءً على الوقت الحالي لضمان حصولنا على قيم مختلفة للمتغير <code>target</code> في كل مرة نلعب فيها، ولاحظ أننا مررنا القيمة 100 إلى الدالة <code>rand.Intn</code> وبالتالي ستكون الأعداد المولَّدة ضمن المجال من 0 إلى 100، وأخيرًا سنستخدِم حلقة <code>for</code> لبدء جمع التخمينات من اللاعب.
</p>

<p>
	تعطينا الدالة <code>fmt.Scanf</code> إمكانية قراءة مدخلات المستخدِم وتخزينها في متغير من اختيارنا، وهنا نريد تخزين القيمة المُدخَلة في المتغير <code>guess</code>، كما نريد أن تكون قيمة هذا المتغير من النوع الصحيح <code>int</code>، لذا سنمرر لهذه الدالة العنصر النائب <code>d%</code> على أساس وسيط أول والذي يشير إلى وجود قيمة من النوع الصحيح، ويكون الوسيط الثاني هو عنوان المتغير <code>guess</code> الذي نريد حفظ القيمة المدخَلة به.
</p>

<p>
	نختبر بعد ذلك فيما إذا كان هناك دخل خاطئ من المستخدِم مثل إدخال نص بدلًا من عدد صحيح ثم نكتب تعليمتَي <code>if</code> بحيث تختبر الأولى فيما إذا كان التخمين الذي أدخله المستخدِم أكبر من قيمة العدد المولَّد ليطبع Too high!‎ وتختبر الثانية فيما إذا كان العدد أصغر ليطبع Too low!‎، وسيكون التخمين في الحالتين خاطئًا، أي القيمة المولّدة لا تتطابق مع التخمين وبالتالي يخسر، طبعًا لاننسى كتابة تعليمة <code>continue</code> بعد كل تعليمة <code>if</code> كما ذكرنا سابقًا، وأخيرًا إذا لم تتحقق أي من الشروط السابقة فإنه يطبع You win!‎ دلالةً إلى أنّ تخمينه صحيح وتتوقف الحلقة لوجود تعليمة <code>break</code>؛ أما إذا لم يكن تخمينه صحيح، فستتكرر الحلقة مرةً أخرى.
</p>

<p>
	لاحظ أنّ استخدام تعليمات <code>if</code> يحجب حقيقة أن مجال القيم التي يُقارن معها المتغير مرتبطة كلها بطريقة ما، كما أنه قد يكون من الصعب معرفة ما إذا كنا قد فاتنا جزء من المجال، وفي المثال التالي سنعدّل المثال السابق باستخدام تعليمة التبديل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1401_16" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"math/rand"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    target </span><span class="pun">:=</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        var guess </span><span class="typ">int</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="str">"Enter a guess: "</span><span class="pun">)</span><span class="pln">
        _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">guess</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Invalid guess: err:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> guess </span><span class="pun">&gt;</span><span class="pln"> target</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Too high!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> guess </span><span class="pun">&lt;</span><span class="pln"> target</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Too low!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"You win!"</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج مُشابهًا لما يلي:
</p>

<pre class="ipsCode">Enter a guess: 25
Too low!
Enter a guess: 28
Too high!
Enter a guess: 27
You win!
</pre>

<p>
	استبدلنا هنا كل تعليمات <code>if</code> بتعليمة التبديل <code>switch</code>، ولاحظ أننا لم نذكر بعد تعليمة التبديل أيّ متغير كما فعلنا في أول مثال من المقال لأن هدفنا هو تجميع الشروط معًا كما ذكرنا، وتتضمن تعليمة التبديل في هذا المثال ثلاث حالات:
</p>

<ul>
	<li>
		الحالة الأولى عندما تكون قيمة المتغير <code>guess</code> أكبر من <code>target</code>.
	</li>
	<li>
		الحالة الثانية عندما تكون قيمة المتغير <code>guess</code> أصغر من <code>target</code>.
	</li>
	<li>
		الحالة الأخيرة هي الحالة الافتراضية <code>default</code>، حيث أنه إذا لم تتحقق أي من الحالات السابقة أي أن <code>guess</code> يساوي <code>target</code> ستُنفَّذ هذه التعليمة ويطبع الرسالة المُحددة، لكن إذا تحققت حالة ما من الحالات السابقة فلن تُنفّذ هذه التعليمة إطلاقًا، إذًا تُشير هذه الحالة إلى أن التخمين يطابق القيمة المولّدة.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: لا حاجة إلى استخدام <code>continue</code> لأن تعليمة التبديل لاتُنفّذ إلا حالة واحدة فقط تلقائيًا.
</p>

<p>
	نلاحظ في الأمثلة السابقة أن حالة واحدة ستُنفّذ، لكن قد تحتاج أحيانًا إلى دمج سلوك عدة حالات معًا، لذا توفِّر تعليمة التبديل كلمةً مفتاحيةً أخرى لإنجاز هذا السلوك.
</p>

<h2>
	التعليمة fallthrough: نفذ الخطوة التالية أيضا
</h2>

<p>
	ربما ترغب بإعادة تنفيذ الشيفرة الموجودة ضمن حالة أخرى، وهنا يمكنك الطلب من جو أن يُشغّل الشيفرة التي تتضمنها الحالة التالية من خلال وضع التعليمة <code>fallthrough</code> في نهاية شيفرة الحالة الحالية، وفي المثال التالي سنُعدِّل المثال الذي عرضناه في بداية المقال والمتعلق بنكهات المثلجات لكي نوضّح كيف يمكننا استخدام هذه التعليمة فيه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1401_18" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    flavors </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"chocolate"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"banana"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> flav </span><span class="pun">:=</span><span class="pln"> range flavors </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">switch</span><span class="pln"> flav </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"strawberry"</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is my favorite!"</span><span class="pun">)</span><span class="pln">
            fallthrough
        </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"vanilla"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"chocolate"</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"is great!"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"I've never tried"</span><span class="pun">,</span><span class="pln"> flav</span><span class="pun">,</span><span class="pln"> </span><span class="str">"before"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">chocolate is great!
vanilla is great!
strawberry is my favorite!
strawberry is great!
I've never tried banana before
</pre>

<p>
	نُعرّف داخل الدالة <code>main</code> شريحةً slice من نكهات المثلجات ثم نستخدِم حلقة <code>for</code> للتكرار على عناصرها ثم نستخدِم تعليمة التبديل ونضع المتغير <code>flav</code> بعد الكلمة <code>switch</code> بحيث تُختبر قيمته وتُنفَّذ إجراءات محددة بناءً عليها:
</p>

<ul>
	<li>
		الحالة الأولى سيطبع رسالةً محددةً عندما تكون قيمة هذا المتغير تساوي vanilla أو chocolate.
	</li>
	<li>
		الحالة الثانية سيطبع strawberry is my favorite!‎ عندما تكون قيمة هذا المتغير تساوي strawberry ثم سيُنفّذ التعليمة <code>fallthrough</code> التي تؤدي إلى تنفيذ شيفرة الحالة التالية لها، وبالتالي سيطبع strawberry is great!‎ أيضًا.
	</li>
	<li>
		الحالة الأخيرة هي الحالة الافتراضية <code>default</code>.
	</li>
</ul>

<p>
	لا يستخدِم المطورون تعليمة <code>fallthrough</code> في <a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%81%D9%8A-%D8%AC%D9%88-go-r1788/" rel="">لغة جو</a> كثيرًا لأنه من الممكن الاستغناء عنها بتعريف <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D9%88%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1962/" rel="">دالة</a> تؤدي الغرض واستدعائها ببساطة، وعمومًا لا يُنصَح باستخدامها.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تساعدنا تعليمة التبديل في التعبير عن ارتباط مجموعة من عمليات المقارنة ببعضها بطريقة ما، وهذا مهم لجعل المطورين الذين يقرؤون الشيفرة يفهمون هذا الارتباط، كما أنها تُسهّل عملية إضافة سلوك جديد وحالات جديدة لاحقًا عندما تدعو الحاجة إلى ذلك وتضمن لنا أنه دومًا سيكون هناك تعليمة افتراضية تُنفَّذ في حال نسينا كتابة حالة من الحالات أو عند عدم تحقق أية حالة من الحالات، لذا جرّب استخدام تعليمة التبديل بدلًا عنها عندما تحتاج إلى كتابة عدة تعليمات <code>if</code> في المرات القادمة، وستجد أنها أسهل بكثير وأكثر قابليةً لإعادة الاستخدام والتصحيح والتعديل.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-write-switch-statements-in-go" rel="external nofollow">How To Construct For Loops in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/" rel="">كيفية كتابة التعليمات الشرطية if في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%81%D9%8A-%D8%AC%D9%88-go-r1788/" rel="">كتابة برنامجك الأول في جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1949</guid><pubDate>Tue, 04 Apr 2023 15:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x62A;&#x639;&#x644;&#x64A;&#x645;&#x627;&#x62A; &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A;&#x629; if &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-if-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1937/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_03/--------Go.png.f594e06128348134d6ddcc072b61f414.png" /></p>
<p>
	لا تخلو أية لغة برمجية من <span ipsnoautolink="true">التعليمات الشرطية Conditional Statements</span> التي تُنفَّذ بناءً على تحقق شرط معيّن، إذ تُعَدّ تعليمات برمجية يمكنها التحكم في تنفيذ شفرات معينة بحسب تحقق شرط ما من عدمه في وقت التنفيذ، وباستخدام التعليمات الشرطية يمكن للبرامج التحقق من استيفاء شروط معينة ومن ثم تنفيذ الشيفرة المقابلة.
</p>

<p>
	تُنفّذ التعليمات البرمجية في الحالة الطبيعية سطرًا سطرًا ومن الأعلى إلى الأسفل؛ أما باستخدام <a href="https://academy.hsoub.com/programming/python/%D8%A7%D8%AA%D8%AE%D8%A7%D8%B0-%D8%A7%D9%84%D9%82%D8%B1%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1892/" rel="">التعليمات الشرطية</a>، فيمكن للبرامج التحقق من استيفاء شروط معينة ومن ثم تنفيذ الشيفرة المقابلة وكسر تسلسل التنفيذ هذا أو تجاوز كتلة من التعليمات، أي باختصار تمكننا التعليمات الشرطية من التحكم بسير عمل البرنامج، وهذه بعض الأمثلة التي سنستخدِم فيها التعليمات الشرطية:
</p>

<ul>
	<li>
		إذا حصل الطالب على أكثر من 65% في الامتحان، فأعلن عن نجاحه؛ وإلا، فأعلن عن رسوبه.
	</li>
	<li>
		إذا كان لديه مال في حسابه، فاطقع منه قيمة الفاتورة، وإلا، فاحسب غرامة.
	</li>
	<li>
		إذا اشتروا 10 برتقالات أو أكثر، فاحسب خصمًا بمقدار 5%؛ وإلا، فلا تفعل.
	</li>
</ul>

<p>
	تقيِّم الشيفرة الشرطية شروطًا ثم تُنفِّذ شيفرةً بناءً على ما إذا تحققت تلك الشروط أم لا، وستتعلم في هذا المقال كيفية كتابة التعليمات الشرطية في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a>.
</p>

<h2>
	التعليمة if
</h2>

<p>
	سنبدأ بالتعليمة ‎if<code>‎</code> والتي تتحقق مما إذا كان شرطًا محدَّدًا محقّقًا true أم لا false، ففي حال تحقق الشرط، فستُنفَّذ الشيفرة المقابلة، وإلا فسيتابع البرنامج في مساره الطبيعي، ولنبدأ بأمثلة عملية توضح ذلك، لذا افتح ملفًا واكتب الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_6" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    grade </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">70</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Passing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أعطينا <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">للمتغير</a> ‎grade<code>‎</code> القيمة الصحيحة ‎70‎ ثم استخدمنا التعليمة ‎if<code>‎</code> لتقييم ما إذا كان أكبر من أو يساوي ‎65‎ وفي تلك الحالة سيطبع البرنامج <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">السلسلة</a> النصية التالية: Passing grade.
</p>

<p>
	احفظ البرنامج بالاسم ‎grade.go‎ ثم نفّذه في بيئة البرمجة المحلية من نافذة الطرفية باستخدام الأمر <code>‎</code>go run grade.go، وفي هذه الحالة تلبي الدرجة 70 تلبي لأنها أكبر من 65، لذلك ستحصل على الخرج التالي عند تنفيذ البرنامج:
</p>

<pre class="ipsCode">Passing grade
</pre>

<p>
	لنغيّر الآن نتيجة هذا البرنامج عبر تغيير قيمة المتغير ‎grade‎ إلى ‎60‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_8" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    grade </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Passing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لن نحصل على أية خرج بعد حفظ وتنفيذ الشيفرة لأنّ الشرط لم يتحقق ولم نأمر البرنامج بتنفيذ تعليمة أخرى.
</p>

<p>
	لنأخذ مثالًا آخرًا، إذ نريد التحقق مما إذا كان رصيد الحساب المصرفي أقل من 0، لذا سننشئ ملفًا باسم ‎account.go‎ ونكتب البرنامج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_10" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    balance </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">5</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> balance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Balance is below 0, add funds now or you will be charged a penalty."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنحصل على الخرج التالي عند تنفيذ البرنامج باستخدام الأمر <code>go run account.go‎‎</code>:
</p>

<pre class="ipsCode">Balance is below 0, add funds now or you will be charged a penalty.
</pre>

<p>
	أعطينا للمتغير <code>‎balance‎</code> القيمة ‎<code>-5</code>‎ وهي أقل من 0 في البرنامج السابق، ولمَّا كان الرصيد مستوفيًا لشرط التعليمة <code>‎if‎</code> أي <code>‎</code>balance &lt; 0‎، فسنحصل على سلسلة نصية في الخرج بمجرد حفظ الشيفرة وتنفيذها، وإذا غيّرنا الرصيد إلى القيمة 0 أو إلى عدد موجب مرةً أخرى، فلن نحصل على أيّ خرج.
</p>

<h2>
	التعليمة else
</h2>

<p>
	قد تريد من البرنامج فعل شيء ما في حال عدم تحقق شرط التعليمة <code>‎if‎</code>، ففي المثال أعلاه نريد طباعة خرج في حال النجاح والرسوب، ولفعل ذلك سنضيف التعليمة <code>‎else‎</code> إلى شرط الدرجة أعلاه وفق الصياغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    grade </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Passing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Failing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تساوي قيمة المتغير <code>‎‎grade‎‎</code> العدد ‎60‎، لذلك فشرط التعليمة <code>‎if‎</code> غير متحقق، وبالتالي لن يطبع البرنامج ‎درجة النجاح‎، إذ تخبر التعليمة <code>‎else‎</code> البرنامج أنه عليه طباعة السلسلة النصية Failing grade، لذا عندما نحفظ البرنامج وننفّذه، فسنحصل على الخرج التالي:
</p>

<pre class="ipsCode">Failing grade
</pre>

<p>
	إذا عدّلنا البرنامج وأعطينا المتغير <code>grade</code> القيمة ‎65‎ أو أعلى منها، فسنحصل بدلًا من ذلك على Passing grade، ولإضافة التعليمة <code>‎else‎</code> إلى مثال الحساب المصرفي، سنعيد كتابة الشيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_14" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    balance </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">522</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> balance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Balance is below 0, add funds now or you will be charged a penalty."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Your balance is 0 or above."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنحصل على الخرج التالي:
</p>

<pre class="ipsCode">Your balance is 0 or above.
</pre>

<p>
	غيّرنا هنا قيمة المتغير <code>‎balance‎</code> إلى عدد موجب لكي تُنفَّذ الشيفرة المقابلة للتعليمة <code>‎else‎</code>، فإذا أردت تنفيذ الشيفرة المقابلة للتعليمة <code>‎if‎</code>، فغيِّر القيمة إلى عدد سالب.
</p>

<p>
	من خلال دمج العبارتين <code>‎if‎</code> و ‎<code>else</code>‎، فأنت تنشئ تعليمة شرطية مزدوجة والتي ستجعل الحاسوب ينفذ شيفرة برمجية معينّة سواءً تحقق شرط <code>‎if‎</code> أم لا.
</p>

<h2>
	التعليمة else if
</h2>

<p>
	عملنا حتى الآن على تعليمات شرطية ثنائية، أي إذا تحقق الشرط، فنفِّذ شيفرةً ما، وإلا، فنفِّذ شيفرةً أخرى فقط، لكن قد تريد في بعض الحالات برنامجًا يتحقق من عدة حالات شرطية، ولأجل هذا سنستخدِم التعليمة Else if والتي تُكتب في جو بالصورة <code>else if</code>، إذ تشبه هذه التعليمة تعليمة ‎<code>if</code>‎ ومهمتها التحقق من شرط إضافي.
</p>

<p>
	قد نرغب في برنامج الحساب المصرفي في الحصول على ثلاثة مخرجات مختلفة مقابلة لثلاث حالات مختلفة:
</p>

<ul>
	<li>
		الرصيد أقل من 0.
	</li>
	<li>
		الرصيد يساوي 0.
	</li>
	<li>
		الرصيد أعلى من 0.
	</li>
</ul>

<p>
	لذا ستوضع التعليمة <code>else if</code> بين التعليمة <code>‎if‎</code> والتعليمة <code>‎else‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_16" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    balance </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">522</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> balance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Balance is below 0, add funds now or you will be charged a penalty."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> balance </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Balance is equal to 0, add funds soon."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Your balance is 0 or above."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هناك الآن ثلاثة مخرجات محتملة يمكن أن تُطبع عند تنفيذ البرنامج وهي:
</p>

<ul>
	<li>
		إذا كان المتغير <code>‎balance‎</code> يساوي ‎0‎، فسنحصل على الخرج من التعليمة <code>else if‎</code> (أي ‎الرصيد يساوي 0، أضف مبلغًا قريبًا‎).
	</li>
	<li>
		إذا ضُبِط المتغير <code>‎balance‎</code>على عدد موجب، فسنحصل على المخرجات من التعليمة <code>‎else‎</code> (أي ‎رصيدك أكبر من 0).
	</li>
	<li>
		إذا ضُبِط المتغير <code>‎balance‎</code>على عدد سالب، فسنحصل على المخرجات من التعليمة <code>‎if‎</code> (أي ‎الحساب فارغ، أضف مبلغا الآن أو ستحصل على غرامة‎).
	</li>
</ul>

<p>
	إذا أردنا أن نأخذ بالحسبان أكثر من ثلاثة احتمالات، فيمكننا كتابة عدة تعليمات <code>else if‎</code> في الشيفرة البرمجية، ولنُعِد الآن كتابة البرنامج ‎grade.go‎ بحيث يقابل كل نطاق من الدرجات العددية درجة حرفية محددة:
</p>

<ul>
	<li>
		الدرجة 90 أو أعلى تكافئ الدرجة A.
	</li>
	<li>
		من 80 إلى 89 تكافئ الدرجة B.
	</li>
	<li>
		من 70 إلى 79 تكافئ الدرجة C.
	</li>
	<li>
		من 65 إلى 69 تكافئ الدرجة D.
	</li>
	<li>
		الدرجة 64 أو أقل تكافئ الدرجة F.
	</li>
</ul>

<p>
	سنحتاج لتنفيذ هذه الشيفرة إلى تعليمة <code>‎if‎</code> واحدة وثلاث تعليمات <code>else if‎</code> وتعليمة <code>‎else‎</code> تعالج جميع الحالات الأخرى، لذا دعنا نعيد كتابة الشيفرة من المثال أعلاه لطباعة سلسلة نصية مقابلة لكل علامة، إذ يمكننا الإبقاء على التعليمة <code>‎else‎</code> كما هي.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_18" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    grade </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">90</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"A grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">80</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"B grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">70</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"C grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"D grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Failing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنفّذ تعليمات <code>else if‎</code> بالترتيب، وسيكمل هذا البرنامج الخطوات التالية:
</p>

<ul>
	<li>
		إذا كانت الدرجة أكبر من 90، فسيطبع البرنامج الدرجة A، وإذا كانت الدرجة أقل من 90، فسيستمر البرنامج إلى التعليمة التالية.
	</li>
	<li>
		إذا كانت الدرجة أكبر من أو تساوي 80، فسيطبع البرنامج الدرجة B‎، إذا كانت الدرجة تساوي 79 أو أقل، فسيستمر البرنامج إلى التعليمة التالية.
	</li>
	<li>
		إذا كانت الدرجة أكبر من أو تساوي 70، فسيطبعُ البرنامجُ الدرجة C، إذا كانت الدرجة تساوي 69 أو أقل، فسيستمر البرنامج إلى التعليمة التالية.
	</li>
	<li>
		إذا كانت الدرجة أكبر من أو تساوي 65، فسيطبع البرنامج الدرجة D، وإذا كانت الدرجة تساوي 64 أو أقل، فسيستمر البرنامج إلى التعليمة التالية.
	</li>
	<li>
		سيطبع البرنامج ‎Failing grade لأنه لم تستوفى أي من الشروط المذكورة أعلاه.
	</li>
</ul>

<h2>
	تعليمات if المتداخلة
</h2>

<p>
	يمكنك الانتقال إلى التعليمات الشرطية المتداخلة بعد أن تتعود على التعليمات <code>‎if‎</code> و <code>else if‎</code> و <code>‎else</code>، إذ يمكننا استخدام تعليمات <code>‎if‎</code> المتداخلة في الحالات التي نريد فيها التحقق من شرط ثانوي بعد التأكد من تحقق الشرط الرئيسي، وبالتالي يمكننا حشر تعليمة if-else داخل تعليمة if-else أخرى، ولنلقِ نظرةً على صياغة <code>‎if‎</code> المتداخلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_20" style=""><span class="kwd">if</span><span class="pln"> statement1 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الخارجية if تعليمة</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"true"</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> nested_statement </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة if تعليمة</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"yes"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة else تعليمة</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"no"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الخارجية else تعليمة</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"false"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هناك عدة مخرجات محتملة لهذه الشيفرة:
</p>

<ul>
	<li>
		إذا كانت التعليمة <code>‎statement1‎</code> صحيحةً، فسيتحقق البرنامج مما إذا كانت <code>‎nested_statement‎</code> صحيحةً أيضًا، فإذا كانت كلتا الحالتين صحيحتين، فسنحصل على المخرجات التالية:
	</li>
</ul>

<pre class="ipsCode">true
yes
</pre>

<ul>
	<li>
		ولكن إذا كانت <code>‎statement1‎</code> صحيحةً و <code>‎nested_statement‎</code> خاطئةً، فسنحصل على المخرجات التالية:
	</li>
</ul>

<pre class="ipsCode">true
no
</pre>

<ul>
	<li>
		وإذا كانت <code>‎statement1‎</code> خاطئةً، فلن تُنفّذ تعليمة if-else المتداخلة على أيّ حال، لذلك ستُنفّذ التعليمة <code>‎else‎</code> وحدها وستكون المخرجات كما يلي:
	</li>
</ul>

<pre class="ipsCode">false
</pre>

<p>
	يمكن أيضًا استخدام عدة تعليمات <code>‎if‎</code> متداخلة في الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_22" style=""><span class="kwd">if</span><span class="pln"> statement1 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الخارجية if</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"hello world"</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> nested_statement1 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الأولى if</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"yes"</span><span class="pun">)</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> nested_statement2 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الأولى else if</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"maybe"</span><span class="pun">)</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الأولى else</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"no"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> statement2 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الخارجية else if</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"hello galaxy"</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> nested_statement3 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الثانية if</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"yes"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> nested_statement4 </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الثانية else if</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"maybe"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// المتداخلة الثانية else</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"no"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// الخارجية else</span><span class="pln">
    statement</span><span class="pun">(</span><span class="str">"hello universe"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	توجد في الشيفرة البرمجية أعلاه تعليمات <code>‎if‎</code> و <code>else if</code> متداخلة داخل كل تعليمات <code>‎if‎</code>، إذ سيفسح هذا مجالًا لمزيد من الخيارات في كل حالة.
</p>

<p>
	دعنا نلقي نظرةً على مثال لتعليمات <code>‎if‎</code> متداخلة في البرنامج ‎grade.go، إذ يمكننا التحقق أولًا مما إذا كان الطالب قد حقق درجة النجاح (أكبر من أو تساوي 65%) ثم نحدد العلامة المقابلة للدرجة، فإذا لم يحقق الطالب درجة النجاح، فلا داعي للبحث عن العلامة المقابلة للدرجة، وبدلًا من ذلك، يمكن أن نجعل البرنامج يطبع سلسلة نصية فيها إعلان عن رسوب الطالب، وبالتالي ستبدو الشيفرة المعدلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_24" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    grade </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">92</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="str">"Passing grade of: "</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">90</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"A"</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">80</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"B"</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">70</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"C"</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"D"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Failing grade"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا أعطينا للمتغير <code>‎grade‎</code> القيمة ‎92‎، فسيتحقق الشرط الأول وسيطبع البرنامج العبارة "‎Passing grade of:‎"، بعد ذلك سيتحقق مما إذا كانت الدرجة أكبر من أو تساوي 90، وبما أنّ هذا الشرط محقق أيضًا، فستُطبع ‎A‎؛ أما إذا أعطينا للمتغير <code>‎grade‎</code> القيمة ‎60‎، فلن يتحقق الشرط الأول، لذلك سيتخطى البرنامج تعليمات <code>‎if‎</code> المتداخلة وينتقل إلى التعليمة ‎<code>else</code>‎ ويطبع ‎Failing grade.
</p>

<p>
	يمكننا بالطبع إضافة المزيد من الخيارات واستخدام طبقة ثانية من تعليمات <code>‎if‎</code> المتداخلة، فربما نودّ إضافة الدرجات التفصيلية A+‎ و A و A-‎، إذ يمكننا إجراء ذلك عن طريق التحقق أولًا من اجتياز درجة النجاح ثم التحقق مما إذا كانت الدرجة تساوي 90 أو أعلى ثم التحقق مما إذا كانت الدرجة تتجاوز 96، وفي تلك الحالة ستقابل العلامة A+، وإليك المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_617_26" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="str">"Passing grade of: "</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">90</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">96</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"A+"</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">93</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> grade </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">96</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"A"</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"A-"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	سيؤدي البرنامج السابق ما يلي في حال تعيين المتغير <code>‎grade‎</code> على القيمة ‎96‎:
</p>

<ul>
	<li>
		التحقق مما إذا كانت الدرجة أكبر من أو تساوي 65 (صحيح).
	</li>
	<li>
		طباعة ‎Passing grade of:‎
	</li>
	<li>
		التحقق مما إذا كانت الدرجة أكبر من أو تساوي 90 (صحيح).
	</li>
	<li>
		التحقق مما إذا كانت الدرجة أكبر من 96 (خطأ).
	</li>
	<li>
		التحقق مما إذا كانت الدرجة أكبر من 93 وأقل من أو تساوي 96 (صحيح).
	</li>
	<li>
		طباعة A.
	</li>
	<li>
		تجاوز التعليمات الشرطية المتداخلة وتنفيذ باقي الشيفرة.
	</li>
</ul>

<p>
	سيكون خرج البرنامج إذا كانت الدرجة تساوي 96 كما يلي:
</p>

<pre class="ipsCode">Passing grade of: A
</pre>

<p>
	تساعد تعليمات <code>‎if‎</code> المتداخلة على إضافة عدة مستويات من الشروط الفرعية إلى الشيفرة.
</p>

<h2>
	الخاتمة
</h2>

<p>
	ستتحكم باستخدام التعليمات الشرطية في مسار عمل البرنامج أي تدفق تنفيذ الشيفرة، إذ تطلب التعليمات الشرطية من البرنامج التحقق من استيفاء شرط معيّن من عدمه، فإذا استُوفي الشرط، فستُنفّذ شيفرة معينة، وإلا، فسيستمر البرنامج وينتقل إلى الأسطر التالية.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-write-conditional-statements-in-go" rel="external nofollow">How To Write Conditional Statements in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D9%81%D9%87%D9%85-%D9%85%D8%AC%D8%A7%D9%84-%D8%B1%D8%A4%D9%8A%D8%A9-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-visibility-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1916/" rel="">فهم مجال رؤية الحزم Visibility في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">تعلم أساسيات البرمجة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1937</guid><pubDate>Mon, 27 Mar 2023 13:09:00 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x645;&#x62C;&#x627;&#x644; &#x631;&#x624;&#x64A;&#x629; &#x627;&#x644;&#x62D;&#x632;&#x645; Visibility &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D9%81%D9%87%D9%85-%D9%85%D8%AC%D8%A7%D9%84-%D8%B1%D8%A4%D9%8A%D8%A9-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-visibility-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1916/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/59004648_------Go-21.png.4c1921d1d0373a969800908fce396242.png" /></p>
<p>
	الهدف من إنشاء الحزم في لغة جو أو في أي لغة أخرى هو جعل هذه الحزمة متاحة للاستخدام وسهلة الوصول في أيّ وقت من قِبَل مطورين آخرين أو حتى نحن، إذ تُستخدَم هذه الحزم ضمن برمجيات محددة أو بوصفها جزءًا من حزم أكثر تعقيدًا أو أعلى مستوى، لكن لايمكن الوصول إلى جميع الحزم من خارج الحزمة نفسها، ويعتمد ذلك على نطاق رؤيتها.
</p>

<p>
	تُعَدّ الرؤية Visibility هي النطاق الذي يمكن الوصول للحزمة ضمنه، فإذا صرّحت مثلًا عن متغير داخل دالة ضمن حزمة A، فلن تتمكن من الوصول إلى هذا المتغير إلى ضمن الدالة التي صُرّح عنه فيها وضمن الحزمة A فقط، في حين إذا صرّحت عن المتغير نفسه ضمن الحزمة وليس بداخل دالة أو أيّ نطاق آخر، فيمكنك السماح للحزم الأخرى بالوصول إلى هذا المتغير أو لا.
</p>

<p>
	عند التفكير بكتابة شيفرة مريحة ومرتّبة ومنظّمة لا بدّ من أن تكون دقيقًا في ضبط رؤية الحزم في مشروعك، ولاسيما عندما يكون من المحتمل تعديل ملفات مشروعك باستمرار، فعندما تحتاج إلى إجراء تعديلات مثل إصلاح <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">زلة برمجية</a> أو تحسين أداء أو تغيير دوال …إلخ بطريقة منظمة وبدون فوضى أو إرباك للمطورين الآخرين الذي يستخدمون الحزمة، فلا بدّ من أن تكون دقيقًا في تحديد الرؤية.
</p>

<p>
	تتمثّل إحدى طرق الضبط الدقيق لمثل هذه العمليات في تقييد الوصول -أي تقييد الرؤية-، بحيث تسمح بالوصول إلى أجزاء مُحددة فقط من الحزمة -أي الأجزاء القابلة للاستخدام فقط-، وبذلك تتمكّن من إجراء التغييرات الداخلية على حِزَمك مع تقليل احتمالية التأثير على استخدام المطورين للحزمة.
</p>

<p>
	ستتعلم في هذا المقال كيفية التحكم في رؤية الحزمة، وكذلك كيفية حماية أجزاء من التعليمات البرمجية الخاصة بك والتي يجب استخدامها فقط داخل حزمتك، إذ سننشئ أداة تسجيل لتسجيل الرسائل وتصحيح الأخطاء باستخدام حزم تتضمن عناصر لها درجات متفاوتة من الرؤية.
</p>

<h2>
	المتطلبات
</h2>

<ul>
	<li>
		أن يكون لديك مساحة عمل خاصة في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a>، فإذا لم يكن لديك، فاتبع سلسلة المقالات التالية، فقد تحدّثنا عن ذلك في بداية السلسلة
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-r1766/" rel="">تثبيت لغة جو Go وإعداد بيئة برمجة محلية على أبونتو Ubuntu</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%85%D8%A7%D9%83-macos-r1767/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على نظام ماك macOS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-r1768/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على ويندوز</a>
	</li>
</ul>

<p>
	سيعتمد المقال على بنية المجلد التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_9" style=""><span class="pun">.</span><span class="pln">
</span><span class="pun">├──</span><span class="pln"> bin 
</span><span class="pun">│</span><span class="pln"> 
</span><span class="pun">└──</span><span class="pln"> src
    </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
        </span><span class="pun">└──</span><span class="pln"> gopherguides</span></pre>

<h2>
	العناصر المصدرة وغير المصدرة
</h2>

<p>
	لا تمتلك لغة جو محددات وصول لتحديد الرؤية مثل عام <code>public</code> وخاص <code>private</code> ومحمي <code>protected</code> كما في باقي <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a>، إذ تحدِّد لغة جو إمكانية رؤية العناصر اعتمادًا على ما إذا كان مُصدّرًا أم لا وذلك وفقًا لكيفية التصريح عنه، فإذا كان مصدّرًا فهو مرئي من خارج الحزمة وإلا فهو مرئي فقط داخل الحزمة التي أُنشئ فيها.
</p>

<p>
	لكي نجعل عنصرًا ما -مثل متغير أو دالة أو نوع بيانات جديد …إلخ- داخل الحزمة مُصدّرًا، سنكتب أول محرف منه كبيرًا، أي إذا كان اسم الدالة <code>hsoub</code>، فستكون مرئيةً فقط ضمن الحزمة نفسها وتكون غير مُصدّرة؛ أما إذا كتبناها <code>Hsoub</code>، فستكون مرئيةً من خارج الحزمة وتكون مُصدّرة.
</p>

<p>
	لاحظ المثال التالي وانتبه لحالة أول محرف في كل التصريحات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_13" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var </span><span class="typ">Greeting</span><span class="pln"> string

func </span><span class="typ">Hello</span><span class="pun">(</span><span class="pln">name string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="typ">Greeting</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من الواضح أنّ هذه الشيفرة موجودة ضمن الحزمة <code>greet</code>، ولاحظ أننا صرّحنا عن متغير اسمه <code>Greeting</code> وجعلنا أول محرف كبيرًا، لذا فهذا المتغير سيكون مُصدّرًا ويمكن رؤيته من خارج الحزمة، وينطبق الأمر نفسه على الدالة <code>Hell</code>، فقد كتبنا أول محرف منها كبيرًا.
</p>

<p>
	كما ذكرنا سابقًا، إنّ تحديد إمكانية الوصول أو الرؤية يجعل الشيفرة منظمةً ويمنع حدوث فوضى أو إرباك للمطورين الآخرين الذي يستخدِمون الحزمة، كما يمنع أو يقلل من إمكانية حدوث تأثيرات سلبية على مشاريعهم التي تعتمد على حزمتك.
</p>

<h2>
	تحديد رؤية الحزمة
</h2>

<p>
	سنُنشئ الحزمة <code>logging</code> مع الأخذ بالحسبان ما نريده مرئيًا وما نريده غير مرئي لكي يكون لدينا نظرة أوضح عن آلية عمل قابلية الرؤية في برامجنا.
</p>

<p>
	ستكون هذه الحزمة مسؤولةً عن تسجيل أيّ رسالة من البرنامج إلى وحدة التحكم console، كما يُحدد المستوى الذي يحدث عنده التسجيل، إذ يصف المستوى نوع السجل وسيكون أحد الحالات الثلاث: معلومات <code>info</code> أو تحذير <code>warning</code> أو خطأ <code>error</code>، لذا أنشئ بدايةً مجلد الحزمة <code>logging</code> داخل المجلد src كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_15" style=""><span class="pln">$ mkdir logging</span></pre>

<p>
	انتقل إلى مجلد الحزمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_17" style=""><span class="pln">$ cd logging</span></pre>

<p>
	أنشئ ملف logging.go باستخدام محرر شيفرات مثل نانو nano:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_19" style=""><span class="pln">$ nano logging</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	ضع فيه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_21" style=""><span class="pln">package logging

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

var debug </span><span class="kwd">bool</span><span class="pln">

func </span><span class="typ">Debug</span><span class="pun">(</span><span class="pln">b </span><span class="kwd">bool</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    debug </span><span class="pun">=</span><span class="pln"> b
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Log</span><span class="pun">(</span><span class="pln">statement string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">!</span><span class="pln">debug </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%s %s\n"</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">Format</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">),</span><span class="pln"> statement</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تصف التعليمة الأولى في هذه الشيفرة أننا ضمن الحزمة <code>logging</code>، وتوجد لدينا ضمن هذه الحزمة دالتين مُصدّرتين هما <code>Debug</code> و <code>Log</code>، وبالتالي يمكن استدعاء هذه الدوال من أيّ حزمة أخرى تستورد الحزمة <code>logging</code>، ولدينا أيضًا متغير غير مُصدّر اسمه <code>debug</code>، وبالتالي لايمكن الوصول إليه إلى ضمن الحزمة.
</p>

<p>
	على الرغم من أنه لدينا متغير ودالة بالاسم نفسه "debug"، إلا أنهما مختلفان، فالدالة بدأت بمحرف كبير؛ أما المتغير، فقد بدأ بمحرف صغير ولغة جو حساسة لحالة المحارف.
</p>

<p>
	احفظ الملف بعد وضع الشيفرة فيه، ولاستخدام الحزمة في مكان آخر، يجب استيرادها، لذا سنُنشئ حزمةً جديدةً ونجرب عليها، وبالتالي انتقل إلى المجلد logging وأنشئ مجلدًا اسمه cmd وانتقل إليه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_23" style=""><span class="pln">$ cd </span><span class="pun">..</span><span class="pln">
$ mkdir cmd
$ cd cmd</span></pre>

<p>
	أنشئ الملف main.go بداخله:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_25" style=""><span class="pln">$ nano main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	أضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_27" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logging</span><span class="pun">.</span><span class="typ">Debug</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logging</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"This is a debug statement..."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أصبح لدينا الآن كامل الشيفرة المطلوب، لكن نحتاج قبل تشغيلها إلى إنشاء ملفَي ضبط حتى تعمل التعليمات البرمجية بطريقة صحيحة.
</p>

<p>
	تُستخدَم وحدات لغة جو Go Modules لضبط اعتماديات الحزمة لاستيراد الموارد، إذ تُعَدّ وحدات لغة جو ملفات ضبط موضوعة في مجلد الحزمة الخاص بك وتخبر المُصرّف بمكان استيراد الحزم منه، ولن نتحدث عن وحدات لغة جو في هذا المقال، لكن سنكتب السطرين التاليين لكي تعمل الشيفرة السابقة، لذا افتح ملف go.mod ضمن المجلد cmd:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_29" style=""><span class="pln">$ nano go</span><span class="pun">.</span><span class="pln">mod</span></pre>

<p>
	ثم ضع السطرين التاليين فيه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_31" style=""><span class="pln">module github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gopherguides</span><span class="pun">/</span><span class="pln">cmd
replace github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gopherguides</span><span class="pun">/</span><span class="pln">logging </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">../</span><span class="pln">logging</span></pre>

<p>
	يُخبر السطر الأول المُصرّف أنّ الحزمة <code>cmd</code> لديها مسار الملف <code>github.com/gopherguides/cmd</code>؛ أما السطر الثاني، فيُخبر المُصرّف أنّ الحزمة <code>github.com/gopherguides/logging</code> يمكن العثور عليها محليًا على القرص في المجلد <code>‎../logging</code>.
</p>

<p>
	نحتاج إيضًا إلى وجود ملف go.mod بداخل الحزمة <code>logging</code>، لذا سننتقل إلى مجلدها ثم سننشئ هذا الملف بداخله:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_33" style=""><span class="pln">$ cd </span><span class="pun">../</span><span class="pln">logging
$ nano go</span><span class="pun">.</span><span class="pln">mod</span></pre>

<p>
	أضف الشيفرة التالية إلى الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_35" style=""><span class="pln">module github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gopherguides</span><span class="pun">/</span><span class="pln">logging</span></pre>

<p>
	يخبر هذا المترجم أنّ حزمة <code>logging</code> التي أنشأناها هي الحزمة <code>github.com/gopherguides/logging</code>، إذ سيسمح لنا ذلك باستيراد الحزمة من داخل الحزمة <code>main</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_37" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logging</span><span class="pun">.</span><span class="typ">Debug</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logging</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"This is a debug statement..."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب أن يكون لديك الآن بنية المجلد التالية:
</p>

<pre class="ipsCode">├── cmd
│   ├── go.mod
│   └── main.go
└── logging
    ├── go.mod
    └── logging.go
</pre>

<p>
	أصبح بإمكاننا الآن تشغيل البرنامج <code>main</code> من حزمة <code>cmd</code> بالأوامر التالية بعد أن أنشأنا جميع ملفات الضبط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_41" style=""><span class="pln">$ cd </span><span class="pun">../</span><span class="pln">cmd
$ go run main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	سنحصل على رسالة تطبع التوقيت وتقول أن هذه تعليمة تنقيح debug:
</p>

<pre class="ipsCode" id="ips_uid_2454_54">2019-08-28T11:36:09-05:00 This is a debug statement...</pre>

<p>
	يطبع البرنامج الوقت الحالي بتنسيق RFC 3339 متبوعًا بالتعليمة التي أرسلناها إلى المُسجّل logger، وقد صُمِّم RFC 3339 لتمثيل الوقت على الإنترنت ومن الشائع استخدامه في ملفات التسجيل والتتبع log files.
</p>

<p>
	بما أن الدالتين <code>Debug</code> و <code>Log</code> هما دوال مُصدّرة، لذا يمكن استخدامهما في الحزمة <code>main</code>، لكن لا يمكن استخدام المتغير <code>debug</code> في حزمة <code>logging</code>، وإذا حاولت الوصول إليه، فستحصل على خطأ في وقت التصريف compile-time error.
</p>

<p>
	سنضيف السطر <code>(fmt.Println(logging.debug</code> إلى main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_45" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logging</span><span class="pun">.</span><span class="typ">Debug</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logging</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"This is a debug statement..."</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">logging</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ وشغل الملف، إذ ستحصل على الخطأ التالي (لا يمكن الإشارة إلى العنصر debug لأنه غير مُصدّر):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_47" style=""><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
</span><span class="pun">./</span><span class="pln">main</span><span class="pun">.</span><span class="pln">go</span><span class="pun">:</span><span class="lit">10</span><span class="pun">:</span><span class="lit">14</span><span class="pun">:</span><span class="pln"> cannot refer to unexported name logging</span><span class="pun">.</span><span class="pln">debug</span></pre>

<p>
	سنتعرّف الآن على كيفية تصدير الحقول والتوابع من داخل السجلات structs بعد أن تعرّفنا على الملفات المُصدّرة وغير المُصدّرة.
</p>

<h2>
	نطاق الرؤية داخل السجلات structs
</h2>

<p>
	تحدّثنا في الأمثلة السابقة عن إمكانية الوصول إلى عنصر ينتمي إلى حزمة مُحددة من حزمة أخرى، كذلك رأينا أنه يمكننا تعديل العناصر التي تكون مُصدّرة. غالبًا ستسير الأمور على مايُرام، لكن في بعض الحالات قد تظهر لدينا بعض المشاكل. مثلًا، عندما تستخدم أكثر من حزمة متغير وتعدّل إحداها على قيمته، فسيكون التعديل على النسخة نفسها والتي ستنعكس على كل تلك الحزم التي تصل إليه، وبالتالي ستحدث لدينا مشكلة عدم اتساق في البيانات.
</p>

<p>
	تخيل أن تضبط المتغير <code>Debug</code> على <code>true</code> ويأتي شخص آخر لا تعرفه يستخدم الحزمة نفسها ويضبطه على <code>false</code>، لذا سنحل هذه المشكلة من خلال استخدام مفهوم النسخ الذي تتبناه السجلات Structs في جو، وبالتالي كل شخص يستخدِم هذه الحزمة سيأخذ نسخةً مستقلةً منها، وبالتالي سنتجنب مثل هذه المشاكل.
</p>

<p>
	سنعدّل الآن الحزمة <code>logging</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_49" style=""><span class="pln">package logging

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">Logger</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    timeFormat string
    debug      </span><span class="kwd">bool</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">New</span><span class="pun">(</span><span class="pln">timeFormat string</span><span class="pun">,</span><span class="pln"> debug </span><span class="kwd">bool</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="typ">Logger</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Logger</span><span class="pun">{</span><span class="pln">
        timeFormat</span><span class="pun">:</span><span class="pln"> timeFormat</span><span class="pun">,</span><span class="pln">
        debug</span><span class="pun">:</span><span class="pln">      debug</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">l </span><span class="pun">*</span><span class="typ">Logger</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Log</span><span class="pun">(</span><span class="pln">s string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">!</span><span class="pln">l</span><span class="pun">.</span><span class="pln">debug </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%s %s\n"</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">Format</span><span class="pun">(</span><span class="pln">l</span><span class="pun">.</span><span class="pln">timeFormat</span><span class="pun">),</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أنشأنا هنا السجل <code>Logger</code> الذي سيضم العناصر غير المُصدّرة وتنسيق الوقت <code>timeFormat</code> المطلوب طباعته والمتغير <code>debug</code> وقيمته سواءً كانت <code>true</code> أو <code>false</code>.
</p>

<p>
	تضبط الدالة <code>New</code> الحالة الأولية لإنشاء السجل <code>logger</code> داخليًا ضمن المتغيران <code>timeFormat</code> و <code>debug</code> غير المُصدَّران، كما أنشأنا التابع <code>Log</code> بداخل هذا السجل الذي يأخذ المعلومات المراد طباعتها، كما يوجد بداخل التابع <code>Log</code> مرجع reference يعود إلى متغير الدالة المحلية <code>l</code> الخاص به للحصول على سماحية الوصول مرةً أخرى إلى الحقول الداخلية مثل <code>l.timeFormat</code> و <code>l.debug</code>.
</p>

<p>
	سيسمح لنا هذا النهج بإنشاء مسجل <code>Logger</code> في العديد من الحزم المختلفة واستخدامه باستقلال عن الحزم الأخرى له، ولاستخدامه في حزمة أخرى سنعدّل ملف cmd/main.go كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_51" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logger </span><span class="pun">:=</span><span class="pln"> logging</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"This is a debug statement..."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بتشغيل البرنامج سنحصل على الخرج التالي:
</p>

<pre class="ipsCode">2019-08-28T11:56:49-05:00 This is a debug statement...
</pre>

<p>
	أنشأنا في هذا المثال نسخةً من المُسجّل logger من خلال استدعاء الدالة المُصدّرة <code>New</code>، كما خزّنا مرجعًا لهذه النسخة في متغير المُسجّل <code>logger</code>، ويمكننا الآن استدعاء <code>logging.Log</code> لطباعة المعلومات.
</p>

<p>
	إذا حاولنا الإشارة إلى حقول غير مُصدّرة من <code>Logger</code> مثل الحقل <code>timeFormat</code>، فسنحصل على خطأ في وقت التصريف، لذا جرّب إضافة السطر <code>(fmt.Println(logger.timeFormat</code> إلى الملف cmd/main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_57" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logger </span><span class="pun">:=</span><span class="pln"> logging</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"This is a debug statement..."</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">logger</span><span class="pun">.</span><span class="pln">timeFormat</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستحصل على الخطأ التالي (لا يمكن الإشارة إلى حقل أو دالة غير مصدرة):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_59" style=""><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
cmd</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">go</span><span class="pun">:</span><span class="lit">14</span><span class="pun">:</span><span class="lit">20</span><span class="pun">:</span><span class="pln"> logger</span><span class="pun">.</span><span class="pln">timeFormat undefined </span><span class="pun">(</span><span class="pln">cannot refer to unexported field or method timeFormat</span><span class="pun">)</span></pre>

<p>
	سيُلاحظ المُصرّف أنّ <code>logger.timeFormat</code> غير مُصدّر، وبالتالي لا يمكن الوصول إليه من الحزمة <code>logging</code>.
</p>

<h2>
	نطاق الرؤية في التوابع
</h2>

<p>
	يمكننا تصدير أو عدم تصدير الدوال بطريقة الحقول ضمن السجلات Structs نفسها، ولتوضيح ذلك سنضيف مستويات التسجيل إلى المسجل logger الخاص بنا، إذ تُعَدّ مستويات التسجيل وسيلةً لتصنيف السجلات logs الخاصة بك، بحيث يمكنك البحث فيها عن أنواع معينة من الأحداث، وتكون المستويات التي سنضعها في المسجل logger كما يلي:
</p>

<ul>
	<li>
		مستوى المعلومات <code>info</code>: تمثِّل الأحداث التي تُعلِم المستخدِم بإجراء ما مثل بدء البرنامج <code>Program started</code> أو إرسال البريد الإلكتروني <code>Email sent</code>، كما تساعدنا في تصحيح الأخطاء وتتبع أجزاء من برنامجنا لمعرفة ما إذا كان السلوك المتوقع قد حدث أم لا.
	</li>
	<li>
		مستوى التحذير <code>warning</code>: تشير هذه الأحداث إلى حدوث أمر غير متوقع أو قد يُسبب مشاكل لاحقًا، لكنها ليست أخطاءً مثل فشل إرسال البريد الإلكتروني وإعادة محاولة الإرسالة <code>Email failed to send, retrying</code>، ويمكن القول أنها تساعدنا في رؤية أجزاء من برنامجنا لا تسير كما هو متوقع لها.
	</li>
	<li>
		مستوى الأخطاء <code>error</code>: تشير إلى حدوث أخطاء أو مشاكل في البرنامج مثل الملف غير موجود<code>File not found</code>، فهذه الأحداث هي أخطاء تؤدي إلى فشل البرنامج وبالتالي إيقافه.
	</li>
</ul>

<p>
	قد ترغب في تفعيل أو إيقاف مستويات معينة من التسجيل، خاصةً إذا كان برنامجك لا يعمل كما هو متوقع له وترغب في تصحيح أخطاء البرنامج، لذا سنضيف وظيفة تعدِّل البرنامج بحيث عندما تكون <code>debug</code> مضبوطةً على <code>true</code>، فستُطبع كل رسائل المستويات؛ أما إذا كانت <code>false</code>، فستطبع رسائل الخطأ فقط.
</p>

<p>
	سنضيف مستويات التسجيل إلى الملف logging/logging.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_61" style=""><span class="pln">package logging

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">Logger</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    timeFormat string
    debug      </span><span class="kwd">bool</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">New</span><span class="pun">(</span><span class="pln">timeFormat string</span><span class="pun">,</span><span class="pln"> debug </span><span class="kwd">bool</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="typ">Logger</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Logger</span><span class="pun">{</span><span class="pln">
        timeFormat</span><span class="pun">:</span><span class="pln"> timeFormat</span><span class="pun">,</span><span class="pln">
        debug</span><span class="pun">:</span><span class="pln">      debug</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">l </span><span class="pun">*</span><span class="typ">Logger</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Log</span><span class="pun">(</span><span class="pln">level string</span><span class="pun">,</span><span class="pln"> s string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    level </span><span class="pun">=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">ToLower</span><span class="pun">(</span><span class="pln">level</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">switch</span><span class="pln"> level </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"info"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"warning"</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> l</span><span class="pun">.</span><span class="pln">debug </span><span class="pun">{</span><span class="pln">
            l</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">level</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
        l</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">level</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">l </span><span class="pun">*</span><span class="typ">Logger</span><span class="pun">)</span><span class="pln"> write</span><span class="pun">(</span><span class="pln">level string</span><span class="pun">,</span><span class="pln"> s string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"[%s] %s %s\n"</span><span class="pun">,</span><span class="pln"> level</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">().</span><span class="typ">Format</span><span class="pun">(</span><span class="pln">l</span><span class="pun">.</span><span class="pln">timeFormat</span><span class="pun">),</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أننا صرّحنا عن وسيط جديد للتابع <code>Log</code> هو <code>level</code> بغية تحديد مستوى التسجيل، فإذا كان لدينا رسالة معلومات <code>info</code> أو تحذير <code>warning</code> وكان حقل <code>debug</code> مضبوطًا على <code>true</code>، فسيكتب الرسالة، وإلا فسيتجاهلها؛ أما إذا كانت الرسالة هي رسالة خطأ <code>error</code>، فسيطبعها دومًا.
</p>

<p>
	يوجد تحديد ما إذا كانت الرسالة ستُطبع أم لا في التابع <code>Log</code>، كما عرّفنا أيضًا تابعًا غير مُصدّر يدعى <code>write</code> وهو مَن سيطبع الرسالة في نهاية المطاف.
</p>

<p>
	يمكننا الآن استخدام مستويات التسجيل في الحزم الأخرى من خلال تعديل ملف cmd/main.go ليصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2454_63" style=""><span class="pln">package main

import </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">logger</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> logging</span><span class="pun">.</span><span class="pln">New</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">,</span><span class="pln"> true</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="pln">Log</span><span class="pun">(</span><span class="str">"info"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"starting up service"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="pln">Log</span><span class="pun">(</span><span class="str">"warning"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"no tasks found"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="pln">Log</span><span class="pun">(</span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"exiting: no work performed"</span><span class="pun">)</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	بتشغيل الملف ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">[info] 2019-09-23T20:53:38Z starting up service
[warning] 2019-09-23T20:53:38Z no tasks found
[error] 2019-09-23T20:53:38Z exiting: no work performed
</pre>

<p>
	نلاحظ نجاح استخدام التابع <code>Log</code>، كما يمكننا تمرير الوسيط <code>level</code> من خلال ضبط القيمة <code>false</code> إلى المتغير <code>debug</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_65" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logger </span><span class="pun">:=</span><span class="pln"> logging</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"info"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"starting up service"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"warning"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"no tasks found"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"exiting: no work performed"</span><span class="pun">)</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	سنلاحظ أنه سيطبع فقط رسائل مستوى الخطأ (لم يُنفّذ أيّ عمل):
</p>

<pre class="ipsCode">[error] 2019-08-28T13:58:52-05:00 exiting: no work performed
</pre>

<p>
	إذا حاولت استدعاء التابع <code>write</code> من خارج الحزمة <code>logging</code>، فستحصل على خطأ في وقت التصريف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2454_68" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/logging"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    logger </span><span class="pun">:=</span><span class="pln"> logging</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">RFC3339</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"info"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"starting up service"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"warning"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"no tasks found"</span><span class="pun">)</span><span class="pln">
    logger</span><span class="pun">.</span><span class="typ">Log</span><span class="pun">(</span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"exiting: no work performed"</span><span class="pun">)</span><span class="pln">

    logger</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"log this message..."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">cmd/main.go:16:8: logger.write undefined (cannot refer to unexported field or method logging.(*Logger).write)
</pre>

<p>
	بمجرد أن بلاحظ المُصرّف أنك تحاول الوصول إلى شيء ما أول محرف منه صغير، فإنه يعلم أنه غير مصدّر وسيرمي خطأ تصريف.
</p>

<p>
	يوضّح المسجل في هذا المقال كيف يمكننا كتابة التعليمات البرمجية التي تعرض فقط الأجزاء التي نريد أن تستخدِمها الحزم الأخرى، وبما أننا نتحكم في أجزاء الحزمة التي تظهر خارج الحزمة، فيمكننا لاحقًا إجراء تغييرات دون التأثير على أيّ شيفرة تعتمد على الحزمة الخاصة بنا، فإذا أردنا مثلًا إيقاف تشغيل رسائل مستوى المعلومات فقط عندما يكون <code>debug</code> مضبوطًا على <code>false</code>، فيمكنك إجراء هذا التغيير دون التأثير على أي جزء آخر من <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> الخاصة بك، كما يمكننا أيضًا إجراء تغييرات بأمان على رسالة السجل لتضمين المزيد من المعلومات مثل المجلد الذي كان البرنامج يعمل منه.
</p>

<h2>
	الخاتمة
</h2>

<p>
	وضح هذا المقال كيفية مشاركة الشيفرة بين الحزم المختلفة مع حماية تفاصيل تنفيذ الحزمة الخاصة بك، إذ يتيح لك ذلك تصدير واجهة برمجة تطبيقات بسيطة نادرًا ما تحصل عليها تغييرات للتوافق مع الإصدارات السابقة، بحيث تكون التغييرات الأساسية غالبيتها ضمن ذلك الصندوق الأسود، ويُعَدّ هذا من أفضل الممارسات عند إنشاء الحزم وواجهات برمجة التطبيقات المقابلة لها.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-package-visibility-in-go" rel="external nofollow">Understanding Package Visibility inGo</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<span ipsnoautolink="true">المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1903/" rel="">إنشاء الحزم في لغة جو Go</a></span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%81%D9%8A-%D8%AC%D9%88-go-r1788/" rel="">كتابة برنامجك الأول في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/" rel="">استيراد الحزم في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1916</guid><pubDate>Mon, 06 Mar 2023 16:09:02 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x62D;&#x632;&#x645; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1903/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/992283795_-----Go-20.png.f5e4464a39b453a2620bc5e0f2d5f418.png" /></p>
<p>
	تُعَدّ الحزمة مجموعةً من الملفات الموجودة ضمن مجلد واحد والمتضمّنة لتعليمة الحزمة نفسها في بدايتها، ويمكنك تضمين العديد من الحزم ضمن برنامجك عند الحاجة لبناء برمجيات أكثر تعقيدًا.
</p>

<p>
	تكون بعض الحزم موجودةً في مكتبة جو القياسية وبعضها الآخر يمكنك تثبيته من خلال الأمر <code>go get</code>، كما يمكنك أيضًا إنشاء الحزم الخاصة بك من خلال بناء ملفات لغة جو التي تحتاجها ووضعه ضمن المجلد نفسه مع الالتزام بكتابة تعليمة الحزمة الضرورية في بداية كل ملف، كما ستتعلم في هذا المقال كيفية إنشاء حزم لغة جو الخاصة بك لاستخدامها في برامجك.
</p>

<h2>
	المتطلبات
</h2>

<ul>
	<li>
		أن يكون لديك مساحة عمل خاصة في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a>، فإذا لم يكن لديك، فاتبع سلسلة المقالات التالية، فقد تحدّثنا عن ذلك في بداية السلسلة
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-r1766/" rel="">تثبيت لغة جو Go وإعداد بيئة برمجة محلية على أبونتو Ubuntu</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D9%85%D8%A7%D9%83-macos-r1767/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على نظام ماك macOS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-r1768/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على ويندوز</a>
	</li>
	<li>
		يُفضّل أن تكون قد اطلعت أيضًا على <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/" rel="">المقالة السابقة</a>
	</li>
	<li>
		يُفضّل أن يكون لديك معرفة حول متغير البيئة أو مسار البيئة GOPATH، ويمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-gopath-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1789/" rel="">التعرّف على GOPATH</a>
	</li>
</ul>

<h2>
	كتابة واستيراد الحزم
</h2>

<p>
	تشبه كتابة الحزم كتابة أيّ برنامج آخر في <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">لغة جو</a>، ويمكن أن تتضمن الحزم دوالًا أو متغيرات أو أنواع بيانات خاصة يمكنك استخدامها في برنامجك لاحقًا.
</p>

<p>
	يجب أن تكون ضمن مساحة العمل الخاصة بك قبل إنشاء حزم جديدة، وهذا يعني أن تكون ضمن مسار البيئة <code>gopath</code>، ففي هذا المقال مثلًا سنُنشئ الحزمة <code>greet</code>، لذا سنُنشئ المجلد greet ضمن مسار البيئة وضمن مساحة العمل الخاصة بك، فإذا كنا ضمن مساحة العمل <code>gopherguides</code> وأردنا إنشاء الحزمة <code>greet</code> ضمنها أثناء استخدام جيت هاب Github على أساس مستودع تعليمات برمجية، فسيبدو المجلد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_12" style=""><span class="pun">└──</span><span class="pln"> $GOPATH
    </span><span class="pun">└──</span><span class="pln"> src
        </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
            </span><span class="pun">└──</span><span class="pln"> gopherguides</span></pre>

<p>
	ستكون الحزمة <code>greet</code> ضمن المجلد gopherguides:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_14" style=""><span class="pun">└──</span><span class="pln"> $GOPATH
    </span><span class="pun">└──</span><span class="pln"> src
        </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
            </span><span class="pun">└──</span><span class="pln"> gopherguides
                </span><span class="pun">└──</span><span class="pln"> greet</span></pre>

<p>
	يمكننا الآن إنشاء أول ملف في الحزمة، ويسمى الملف الأساسي -ويسمى أيضًا نقطة الدخول entry point- في الحزمة عادةً باسم الحزمة نفسها، إذًا سنُنشئ الملف greet.go ضمن المجلد greet كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_16" style=""><span class="pun">└──</span><span class="pln"> $GOPATH
    </span><span class="pun">└──</span><span class="pln"> src
        </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
            </span><span class="pun">└──</span><span class="pln"> gopherguides
                </span><span class="pun">└──</span><span class="pln"> greet
                    </span><span class="pun">└──</span><span class="pln"> greet</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	يمكننا بعد إنشاء الملف كتابة التعليمات البرمجية التي نريدها ضمنه، ويكون الهدف من هذه التعليمات عادةً هو الاستخدام في مكان آخر من المشروع، وفي هذه الحالة سننشئ دالة Hello تطبع Hello World، لذا افتح الملف greet.go من خلال محرر الشيفرات الخاص بك واكتب ضمنه التعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_19" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func </span><span class="typ">Hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب دومًا أن نبدأ باسم الحزمة التي نعمل ضمنها لكي نُخبر المصرِّف أنّ هذا الملف هو جزء من الحزمة، لذا كتبنا الكلمة المفتاحية <code>package</code> متبوعةً باسم الحزمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_21" style=""><span class="pln">package greet</span></pre>

<p>
	ثم نكتب اسم الحزم التي نحتاج إلى استخدامها ضمن الملف من خلال وضع أسمائها بعد الكلمة المفتاحية <code>import</code>، وهنا نحتاج إلى حزمة <code>fmt</code> فقط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_23" style=""><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span></pre>

<p>
	أخيرًا سنكتب الدالة <code>Hello</code> التي تستخدِم الحزمة <code>fmt</code> لتنسيق طباعة جملة الخرج:
</p>

<pre class="ipsCode">func Hello() {
    fmt.Println("Hello, World!")
}
</pre>

<p>
	نكون الآن قد انتهينا من إنشاء الملف الأول وأصبح بإمكاننا استخدام الدالة <code>Hello</code> منه وفي المكان الذي نريده.
</p>

<p>
	سنُنشئ الآن حزمةً جديدةً سنسميها <code>example</code>، لذا يجب أن نُنشئ مجلدًا لها بالاسم نفسه، وسننشئه ضمن مساحة العمل نفسها <code>gopherguides</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_25" style=""><span class="pun">└──</span><span class="pln"> $GOPATH
    </span><span class="pun">└──</span><span class="pln"> src
        </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
            </span><span class="pun">└──</span><span class="pln"> gopherguides
                    </span><span class="pun">└──</span><span class="pln"> example</span></pre>

<p>
	الآن وقد أصبح لديك مجلدًا خاصًا بالحزمة، بات بإمكانك إنشاء ملف نقطة الدخول، والذي سيكون ملفًا رئيسيًا -أي ملف تنفيذي-، لذا سنسميه main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_27" style=""><span class="pun">└──</span><span class="pln"> $GOPATH
    </span><span class="pun">└──</span><span class="pln"> src
        </span><span class="pun">└──</span><span class="pln"> github</span><span class="pun">.</span><span class="pln">com
            </span><span class="pun">└──</span><span class="pln"> gopherguides
                </span><span class="pun">└──</span><span class="pln"> example
                    </span><span class="pun">└──</span><span class="pln"> main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	افتح الملف من محرر الشيفرات الخاص بك واكتب التعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_29" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"github.com/gopherguides/greet"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    greet</span><span class="pun">.</span><span class="typ">Hello</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بما أن الدالة التي تريد استخدامها ضمن الملف الرئيسي موجودة ضمن حزمة أخرى، فسيتوجب عليك استدعاؤها من خلال ذكر اسم الحزمة أولًا متبوعًا بنقطة ثم اسم الدالة، فمثلًا وضعنا هنا اسم الحزمة <code>greet</code> ثم نقطة ثم اسم الدالة <code>()greet.Hello</code>، ويمكنك الآن فتح الطرفية وتشغيل البرنامج ضمنها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_31" style=""><span class="pln">go run main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">Hello, World!
</pre>

<p>
	سنضيف بعض المتغيرات إلى ملف greet.go لتتعلم كيفية استخدام المتغيرات ضمن الحزمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_33" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var </span><span class="typ">Shark</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

func </span><span class="typ">Hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم افتح الملف main.go وأضف التعليمة التالية <code>(fmt.Println(greet.Shark</code> لاستدعاء المتغير <code>Shark</code> داخل الدالة <code>fmt.Println</code>، أي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_35" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/greet"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    greet</span><span class="pun">.</span><span class="typ">Hello</span><span class="pun">()</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">greet</span><span class="pun">.</span><span class="typ">Shark</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم شغّل الشيفرة مرةً أخرى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_37" style=""><span class="pln">$ go run main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">Hello, World!
Sammy
</pre>

<p>
	أخيرًا، سننشئ نوع بيانات جديد ضمن ملف greet.go، إذ سننشئ نوع البيانات <code>Octopus</code> الذي يتضمّن الحقلين <code>name</code> و <code>color</code>، كما سنعرّف دالةً تطبع هذه الحقول:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_40" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var </span><span class="typ">Shark</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

type </span><span class="typ">Octopus</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln">  string
    </span><span class="typ">Color</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">o </span><span class="typ">Octopus</span><span class="pun">)</span><span class="pln"> </span><span class="typ">String</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="str">"The octopus's name is %q and is the color %s."</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Color</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سننشئ الآن نسخةً من هذا النوع داخل الملف main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_42" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/greet"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    greet</span><span class="pun">.</span><span class="typ">Hello</span><span class="pun">()</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">greet</span><span class="pun">.</span><span class="typ">Shark</span><span class="pun">)</span><span class="pln">

    oct </span><span class="pun">:=</span><span class="pln"> greet</span><span class="pun">.</span><span class="typ">Octopus</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Name</span><span class="pun">:</span><span class="pln">  </span><span class="str">"Jesse"</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Color</span><span class="pun">:</span><span class="pln"> </span><span class="str">"orange"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">oct</span><span class="pun">.</span><span class="typ">String</span><span class="pun">())</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بمجرّد إنشاء نسخة من النوع <code>Octopus</code> عند كتابة <code>oct := greet.Octopus</code> يُصبح بإمكاننا الوصول إلى الداول والمتغيرات الموجودة ضمنه من الملف main، وبالتالي إمكانية استدعاء الدالة <code>()oct.String</code> من دون الحاجة لكتابة اسم الحزمة <code>greet</code>، كما يمكنك الوصول إلى الحقول بالطريقة نفسها دون الحاجة إلى كتابة اسم الحزمة مثل <code>oct.Color</code>.
</p>

<p>
	يستخدِم التابع <code>String</code> التي يتضمنها النوع <code>Octopus</code> الدالة <code>fmt.Sprintf</code> لإنشاء وإرجاع سلسلة في المكان الذي استُدعي فيه أي في هذه الحالة في الملف <code>main</code>، وسنشغّل البرنامج الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_44" style=""><span class="pln">$ go run main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">Hello, World!
Sammy
The octopus's name is "Jesse" and is the color orange.
</pre>

<p>
	إذًا سيصبح لدينا دالة يمكن استخدامها حيثما نريد لطباعة معلومات عن نوع البيانات الذي عرّفناه من خلال تعريفنا للتابع <code>String</code> ضمن النوع <code>Octopus</code>، فإذا أردت تغيير سلوك هذا التابع لاحقًا، فيمكنك ببساطة تعديله فقط حيثما يكون.
</p>

<h2>
	تصدير الشيفرة
</h2>

<p>
	لاحظ أنّ كل التصريحات داخل الملف <code>greet.go</code> تبدأ بمحرف كبير، ولا تمتلك لغة جو مفاهيم مُحددات الوصول العامة <code>public</code> والخاصة <code>private</code> والمحمية <code>protected</code> كما في باقي اللغات، ويمكن التحكم بالرؤية في لغة جو من خلال الكتابة بمحارف كبيرة، فالمتغيرات أو الدوال أو الأنواع التي تبدأ بمحارف كبيرة تكون مرئيةً من خارج الحزمة -أي عامة- ويُعتبر عندها مُصدّرًا exported.
</p>

<p>
	إذا أضفت تابعًا جديدًا إلى النوع <code>Octopus</code> اسمه <code>reset</code>، فستتمكّن من استدعائه من داخل الحزمة <code>greet</code>، لكن لن تتمكن من استدعائه من الملف main.go لأنه خارج الحزمة <code>greet</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_46" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var </span><span class="typ">Shark</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

type </span><span class="typ">Octopus</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln">  string
    </span><span class="typ">Color</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">o </span><span class="typ">Octopus</span><span class="pun">)</span><span class="pln"> </span><span class="typ">String</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="str">"The octopus's name is %q and is the color %s."</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Color</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">o </span><span class="pun">*</span><span class="typ">Octopus</span><span class="pun">)</span><span class="pln"> reset</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    o</span><span class="pun">.</span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
    o</span><span class="pun">.</span><span class="typ">Color</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا حاولت استدعاء <code>reset</code> من الملف main.go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_48" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/greet"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    greet</span><span class="pun">.</span><span class="typ">Hello</span><span class="pun">()</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">greet</span><span class="pun">.</span><span class="typ">Shark</span><span class="pun">)</span><span class="pln">

    oct </span><span class="pun">:=</span><span class="pln"> greet</span><span class="pun">.</span><span class="typ">Octopus</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Name</span><span class="pun">:</span><span class="pln">  </span><span class="str">"Jesse"</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Color</span><span class="pun">:</span><span class="pln"> </span><span class="str">"orange"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">oct</span><span class="pun">.</span><span class="typ">String</span><span class="pun">())</span><span class="pln">

    oct</span><span class="pun">.</span><span class="pln">reset</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستحصل على الخطأ التالي والذي يقول أنه لا يمكن الإشارة إلى حقل أو دالة غير مصدرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_50" style=""><span class="pln">oct</span><span class="pun">.</span><span class="pln">reset undefined </span><span class="pun">(</span><span class="pln">cannot refer to unexported field or method greet</span><span class="pun">.</span><span class="typ">Octopus</span><span class="pun">.</span><span class="pln">reset</span><span class="pun">)</span></pre>

<p>
	لتصدير دالة <code>reset</code> من <code>Octopus</code>، اجعل المحرف الأول من الدالة كبيرًا، أي <code>Reset</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_52" style=""><span class="pln">package greet

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

var </span><span class="typ">Shark</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

type </span><span class="typ">Octopus</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln">  string
    </span><span class="typ">Color</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">o </span><span class="typ">Octopus</span><span class="pun">)</span><span class="pln"> </span><span class="typ">String</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="str">"The octopus's name is %q and is the color %s."</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> o</span><span class="pun">.</span><span class="typ">Color</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">o </span><span class="pun">*</span><span class="typ">Octopus</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Reset</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    o</span><span class="pun">.</span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
    o</span><span class="pun">.</span><span class="typ">Color</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبالتالي سيصبح بإمكانك استدعائها من الحزمة الأخرى بدون مشاكل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_54" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">

    </span><span class="str">"github.com/gopherguides/greet"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    greet</span><span class="pun">.</span><span class="typ">Hello</span><span class="pun">()</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">greet</span><span class="pun">.</span><span class="typ">Shark</span><span class="pun">)</span><span class="pln">

    oct </span><span class="pun">:=</span><span class="pln"> greet</span><span class="pun">.</span><span class="typ">Octopus</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Name</span><span class="pun">:</span><span class="pln">  </span><span class="str">"Jesse"</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Color</span><span class="pun">:</span><span class="pln"> </span><span class="str">"orange"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">oct</span><span class="pun">.</span><span class="typ">String</span><span class="pun">())</span><span class="pln">

    oct</span><span class="pun">.</span><span class="typ">Reset</span><span class="pun">()</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">oct</span><span class="pun">.</span><span class="typ">String</span><span class="pun">())</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن إذا شغّلت البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_935_56" style=""><span class="pln">$ go run main</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	ستتلقى الخرج التالي:
</p>

<pre class="ipsCode">Hello, World!
Sammy
The octopus's name is "Jesse" and is the color orange
The octopus's name is "" and is the color .
</pre>

<p>
	نلاحظ من خلال استدعاء الدالة <code>Reset</code> أن جميع بيانات الحقول <code>Name</code> و <code>Color</code> قد مسحتها، وعند استدعاء التابع <code>String</code> لاتطبع شيئًا لأن الحقول السابقة قد أصبحت فارغةً.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تشبه كتابة الحزم في لغة جو كتابة أيّ ملف في لغة جو، إلا أن وضعها في مجلد مُختلف سيسمح لك بعزل الشيفرة لإعادة استخدامها في مكان آخر، وقد تحدثنا في هذا المقال عن كيفية تعريف وإنشاء الحزم وكيفية الاستفادة منها في ملفات أخرى وأين يمكن وضعها للوصول إليها.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-write-packages-in-go" rel="external nofollow">How To Write Packages in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/" rel="">استيراد الحزم في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/" rel="">التعرف على الروابط Maps في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1845/" rel="">تحويل أنواع البيانات في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1903</guid><pubDate>Tue, 28 Feb 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x64A;&#x631;&#x627;&#x62F; &#x627;&#x644;&#x62D;&#x632;&#x645; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1902/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/976079286_19------Go.png.b04c8c3154557e250684c2c526fe5ef7.png" /></p>
<p>
	عادةً ما نحتاج إلى استخدام دوال خارجية أخرى في البرنامج، هذه الدوال تكون ضمن حزم خارجية بناها آخرون أو بنيناها بأنفسنا لتقسيم البرنامج إلى عدة ملفات بهدف جعل البرنامج أبسط وأقل تعقيدًا وأكثر أناقةً وقابليةً للفهم.
</p>

<p>
	تُمثّل الحزمة مجلدًا يحتوي على ملف أو عدة ملفات، هذه الملفات هي شيفرات جو قد تتضمن دوال أو أنواع بيانات أو واجهات يمكنك استخدامها في برنامجك الأساسي، وسنتحدث في هذا المقال عن تثبيت الحزم واستيرادها وتسميتها.
</p>

<h2>
	حزمة المكتبة القياسية
</h2>

<p>
	تُعَدّ المكتبة القياسية التي تأتي مع جو مجموعةً من الحزم، إذ تحتوي هذه الحزم على العديد من اللبنات الأساسية لكتابة البرامج المتطورة في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a>، فتحتوي الحزمة <code>fmt</code> مثلًا على العديد من الدوال التي تُسهّل عمليات تنسيق وطباعة السلاسل النصية، كما تحتوي حزمة <code>net/http</code> على دوال تسمح للمطوّر بإنشاء خدمات ويب وإرسال واسترداد البيانات عبر <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">بروتوكول http</a> إضافةً للعديد من الأمور الأخرى.
</p>

<p>
	يجب عليك أولًا استيراد هذه الحزمة باستخدام التعليمة <code>import</code> متبوعة باسم الحزمة للاستفادة من الدوال الموجودة ضمن أيّ حزمة، فيمكنك مثلًا استيراد الحزمة <code>math/rand</code> ضمن الملف random.go لتوليد أعداد عشوائية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_10" style=""><span class="kwd">import</span><span class="pln"> </span><span class="str">"math/rand"</span></pre>

<p>
	عند استيراد حزمة ما داخل برنامج تصبح جميع مكوناتها قابلةً للاستخدام داخل هذا البرنامج لكن بفضاء أسماء منفصل namespace، وهذا يعني أنه يجب الوصول إلى كل دالة من الحزمة الخارجية بالاعتماد على تدوين النقطة dot notation، أي <code>package.function</code>، فللوصول مثلًا إلى الدوال الموجودة في الحزمة السابقة نكتب <code>()rand.Int</code> لتوليد عدد صحيح عشوائي أو <code>()rand.Intn</code> لتوليد عدد عشوائي بين الصفر والعدد المحدَّد.
</p>

<p>
	سنستخدِم في المثال التالي حلقة <code>for</code> لتوليد أعداد عشوائية بالاستعانة بالدوال السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"math/rand"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="lit">25</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون ناتج الخرج كما يلي:
</p>

<pre class="ipsCode">6
12
22
9
6
18
0
15
6
0
</pre>

<p>
	نستورد بدايةً الحزمة <code>math/rand</code> ثم نستخدِم حلقة تتكرر 10 مرات وفي كل مرة تطبع عدد صحيح بين 0 و 25 بحيث تكون الأعداد الناتجة أقل تمامًا من 25 بما أننا مررنا العدد 25 للدالة <code>()rand.Intn</code>، وطبعًا عملية التوليد هي عشوائية، لذا ستحصل على أعداد مختلفة في كل مرة تُنفِّذ فيها هذا المقطع البرمجي.
</p>

<p>
	عند استيراد أكثر من حزمة نضع هذه الحزم بين قوسين <code>()</code> بعد الكلمة <code>import</code> بدلًا من استخدام الكلمة <code>import</code> من أجل كل حزمة، إذ سيجعل هذا الشيفرة مرتبةً أكثر كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_14" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="str">"fmt"</span><span class="pln">
  </span><span class="str">"math/rand"</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	سنستخدِم الحزمة الجديدة التي استوردناها من أجل تنسيق عملية الطباعة في الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_16" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="str">"fmt"</span><span class="pln">
  </span><span class="str">"math/rand"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%d) %d\n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="lit">25</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">0) 6
1) 12
2) 22
3) 9
4) 6
5) 18
6) 0
7) 15
8) 6
9) 0
</pre>

<p>
	تعلّمت في هذا القسم كيفية استيراد الحزم واستخدامها لكتابة برنامج أكثر تعقيدًا، لكن لم نستخدِم إلا الحزم الموجودة في المكتبة القياسية، وفيما يلي سنرى كيفية تثبيت واستخدام الحزم التي كتبها مطورون آخرون.
</p>

<h2>
	تثبيت الحزم
</h2>

<p>
	تحتوي المكتبة القياسية على العديد من الحزم الهامة والمفيدة لكنها لأغراض عامة، لذا يُنشئ المطورون حزمًا خاصةً بهم فوق المكتبة القياسية لتلبية احتياجاتهم الخاصة.
</p>

<p>
	تتضمن أدوات جو الأمر <code>go get</code> الذي يسمح بتثبيت حزم خارجية ضمن بيئة التطوير المحلية الخاصة بك واستخدامها في برنامجك، وعند استخدام هذا الأمر تُشاع الإشارة إلى الحزمة من خلال مسارها الأساسي، كما يمكن أن يكون هذا المسار مسارًا إلى مشروع عام مُستضاف في مستودع شيفرات مثل جيت هاب GitHub، فلاستيراد الحزمة <code>flect</code> مثلًا نكتب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_18" style=""><span class="pln">$ go get github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gobuffalo</span><span class="pun">/</span><span class="pln">flect</span></pre>

<p>
	سيعثر الأمر <code>go get</code> على هذه الحزمة الموجودة على جيت هاب وسيثبتها في <code>GOPATH$</code>، إذ ستُثبّت الحزمة في هذا المثال ضمن المجلد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_20" style=""><span class="pln">$GOPATH</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gobuffalo</span><span class="pun">/</span><span class="pln">flect</span></pre>

<p>
	غالبًا ما تُحدَّث الحزم من قِبل مُطوريها <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">لمعالجة الزلات البرمجية</a> أو إضافة ميزات جديدة، وقد ترغب في هذه الحالة باستخدام أحدث إصدار من تلك الحزمة للاستفادة من الميزات الجديدة أو <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/" rel="">الزلة البرمجية التي عالجوها</a>، إذ يمكنك تحديث حزمة ما باستخدام الراية <code>‎-u</code> مع الأمر <code>go get</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_25" style=""><span class="pln">$ go get </span><span class="pun">-</span><span class="pln">u github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">gobuffalo</span><span class="pun">/</span><span class="pln">flect</span></pre>

<p>
	سيؤدي هذا الأمر أيضًا إلى تثبيت الحزمة إذا لم تكن موجودةً لديك أساسًا، ويؤدي الأمر <code>go get</code> دائمًا إلى تثبيت أحدث إصدار من الحزمة المتاحة، لكن قد ترغب في استخدام حزمة سابقة أو قد تكون هناك نسخة سابقة قد حُدّثت وترغب في استخدامها، ففي هذه الحالة ستحتاج إلى استخدام أداة إدارة الحزم مثل <code>Go Modules</code>، واعتبارًا من الإصدار Go 1.11 اعتُمِدت <code>Go Modules</code> بوصفها أداة إدارة حزم رسمية لجو.
</p>

<h2>
	تسمية الحزم بأسماء بديلة
</h2>

<p>
	قد تحتاج إلى تغيير اسم الحزمة التي تستوردها في حال كان لديك حزمة أخرى تحمل الاسم نفسه، ففي هذه الحالة يمكنك استخدام الكلمة <code>alias</code> لتغيير اسم الحزمة وتجنب تصادم الأسماء وفق الصيغة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_27" style=""><span class="kwd">import</span><span class="pln"> another_name </span><span class="str">"package"</span></pre>

<p>
	سنعدِّل في المثال التالي اسم الحزمة <code>fmt</code> ضمن ملف random.go ليصبح <code>f</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_29" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
 f </span><span class="str">"fmt"</span><span class="pln">
  </span><span class="str">"math/rand"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    f</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%d) %d\n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="lit">25</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كتبنا <code>f.Printf</code> في البرنامج السابق بدلًا من <code>fmt.Printf</code>، وعمومًا لا يُفضَّل في جو استخدام الأسماء البديلة كما في باقي اللغات مثل بايثون لأنه خروج عن النمط الشائع.
</p>

<p>
	عند اللجوء إلى الأسماء البديلة لتجنب حدوث تصادم في الأسماء، يفضَّل إعادة تسمية الحزم المحلية وليس الخارجيّة، فإذا كان لديك مثلًا حزمة أنشأتها اسمها <code>strings</code> وتريد استخدامها في برنامجك إلى جانب حزمة النظام <code>strings</code>، فيُفضّل تسمية الحزمة التي أنشأتها أنت وليس حزمة النظام.
</p>

<p>
	تذكَّر دومًا أنّ سهولة القراءة والوضوح في برنامجك أمر مهم، لذا يجب عليك استخدام الأسماء البديلة فقط لجعل الشيفرة أكثر قابليةً للقراءة أو عندما تحتاج إلى تجنب تضارب الأسماء.
</p>

<h2>
	تنسيق الحزم
</h2>

<p>
	يمكنك فرز الحزم بترتيب معيّن من خلال تنسيق عمليات الاستيراد لجعل شفرتك أكثر اتساقًا ومنع حدوث تغييرات أو إيداعات عشوائية random commits عندما يكون الشيء الوحيد الذي يتغير هو ترتيب فرز عمليات الاستيراد، فمنع الإيداعات العشوائية سيمنع حدوث خلل في التعليمات البرمجية أو ارتباك أثناء مراجعة الشفرة من قِبل الآخرين.
</p>

<p>
	تُنسّق معظم محررات الشيفرات استيراد الحزم تلقائيًا أو يسمحون لك باستخدام الأداة <code>goimports</code>، إذ يُعَدّ استخدام هذه الأداة أمرًا مفيدًا وشائعًا وممارسةً قياسيةً، فالحفاظ على ترتيب الفرز يدويًا قد يكون مُملًا ومعرّضًا للأخطاء، بالإضافة إلى ذلك، إذا أُجريَت أية تغييرات على التنسيق القياسي لفرز الحزم، فستُحدَّث <code>goimports</code> لتعكس تلك التغييرات في التنسيق، مما يضمن لك ولشركائك أنه سيكون لديكم تنسيق متسق لكتل الاستيراد، وإليك ما قد تبدو عليه كتلة الاستيراد قبل التنسيق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_31" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="str">"fmt"</span><span class="pln">
  </span><span class="str">"os"</span><span class="pln">
  </span><span class="str">"github.com/digital/ocean/godo"</span><span class="pln">
  </span><span class="str">"github.com/sammy/foo"</span><span class="pln">
  </span><span class="str">"math/rand"</span><span class="pln">
  </span><span class="str">"github.com/sammy/bar"</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	سيكون لديك الآن التنسيق التالي بتشغيل الأداة <code>goimport</code> -أو في حالة مُحرّر يستخدِم هذه الأداة، فسيؤدي حفظ الملف إلى تشغيله نيابة عنك-:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8108_33" style=""><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="str">"fmt"</span><span class="pln">
  </span><span class="str">"math/rand"</span><span class="pln">
  </span><span class="str">"os"</span><span class="pln">

  </span><span class="str">"github.com/sammy/foo"</span><span class="pln">
  </span><span class="str">"github.com/sammy/bar"</span><span class="pln">

  </span><span class="str">"github.com/digital/ocean/godo"</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لاحظ أنه يُجمِّع حزم المكتبة القياسية أولًا ثم الحزم الخارجية مع فصلها بسطور فارغة مما يجعل من السهل قراءة وفهم الحزم المستخدَمة.
</p>

<p>
	سيؤدي استخدام الأداة <code>goimports</code> إلى الحفاظ على تنسيق جميع كتل الاستيراد بطريقة مناسبة، ويمنع حدوث ارتباك حول التعليمات البرمجية بين المطورين الذين يعملون على الملفات نفسها.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تحدّثنا في هذا المقال عن كيفية استيراد حزم المكتبة القياسية وكيفية استيراد وتثبيت الحزم الخارجية باستخدام <code>go get</code> للاستفادة من محتوياتها، كما تحدّثنا أيضًا عن كيفية تحديث الحزم واستخدام الأسماء البديلة معها، إذ يتيح لنا استخدام الحزم جعل برامجنا أكثر قوةً ومتانةً وقابليةً للصيانة وللاستخدام المتعدِّد من خلال تقسيمه إلى أجزاء مستقلّة.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/importing-packages-in-go" rel="external nofollow">Importing Packages in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%86%D9%87%D9%8A%D8%A7%D8%B1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1901/" rel="">معالجة حالات الانهيار في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%d9%81%d9%87%d9%85%d8%8c-%d8%aa%d9%86%d8%b5%d9%8a%d8%a8-%d9%88%d8%aa%d9%87%d9%8a%d8%a6%d8%a9-%d8%a8%d9%8a%d8%a6%d8%a9-%d8%b9%d9%85%d9%84-%d9%84%d8%ba%d8%a9-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-go-r230/" rel="">فهم، تنصيب وتهيئة بيئة عمل لغة البرمجة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/" rel="">التعرف على الروابط Maps في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1902</guid><pubDate>Tue, 21 Feb 2023 16:09:00 +0000</pubDate></item><item><title>&#x645;&#x639;&#x627;&#x644;&#x62C;&#x629; &#x62D;&#x627;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x627;&#x646;&#x647;&#x64A;&#x627;&#x631; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%86%D9%87%D9%8A%D8%A7%D8%B1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1901/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/708564228_18-----------.png.0a3aa3fb514f32a965d431b21c644e8e.png" /></p>
<p>
	تنقسم الأخطاء التي قد تحدث في البرنامج إلى فئتين رئيسيتين هما أخطاء يتوقع المبرمج حدوثها وأخطاء لم يتوقع حدوثها، وتُعالِج الواجهة <code>error</code> التي تحدّثنا عنها في <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/" rel="">المقال السابق</a> إلى حد كبير الأخطاء التي نتوقعها أثناء كتابة البرامج حتى تلك الأخطاء التي تكون احتمالات حدوثها نادرةً.
</p>

<p>
	تندرج حالات الانهيار Panics تحت الفئة الثانية والتي تؤدي إلى إنهاء البرنامج تلقائيًا والخروج منه، وعادةً تكون الأخطاء الشائعة هي سبب حالات الانهيار، لذا سندرس في هذا المقال بعض الحالات الشائعة التي يمكن أن تؤدي إلى حالات الانهيار، كما سنلقي نظرةً أيضًا على بعض الطرق التي يُمكن أن نتجنب من خلالها حالات الانهيار، وسنستخدم أيضًا تعليمات التأجيل defer statements جنبًا إلى جنب مع الدالة <code>recover</code> لالتقاط حالات الانهيار قبل أن تؤدي إلى إيقاف البرنامج.
</p>

<h2>
	ما هي حالات الانهيار؟
</h2>

<p>
	هناك عمليات محددة في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> تؤدي إلى حالات الانهيار ومن ثم إيقاف البرنامج مباشرةً، وتتمثّل بعض هذه العمليات في محاولة الوصول إلى فهرس لا تتضمنه حدود المصفوفة -أي تجاوز حدود المصفوفة- أو إجراء عمليات توكيد النوع type assertions أو استدعاء توابع على مؤشرات لا تُشير إلى أيّ شيء <code>nil</code> أو استخدام كائنات المزامنة mutexes بطريقة خاطئة أو محاولة العمل مع القنوات المغلقة closed channels، فمعظم هذه المواقف تنتج عن <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">أخطاء أثناء البرمجة</a> ولا يستطيع المُصرِّف اكتشافها أثناء تصريف البرنامج.
</p>

<p>
	بما أن حالات الانهيار تتضمن تفاصيل مفيدةً لحل مشكلة ما، فعادةً ما يستخدِم المطورون حالات الانهيار بوصفها مؤشرًا على ارتكابهم خطأ أثناء تطوير البرنامج.
</p>

<h3>
	حالات الانهيار الناتجة عن تجاوز الحدود
</h3>

<p>
	ستولد جو حالة انهيار في وقت التشغيل runtime عند محاولة الوصول إلى فهرس خارج حدود المصفوفة أو الشريحة، ويجسِّد المثال التالي هكذا حالة، إذ سنحاول الوصول إلى آخر عنصر من الشريحة من خلال القيمة المُعادة من الدالة <code>len</code>، أي من خلال طول الشريحة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_17" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    names </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="pln">
        </span><span class="str">"lobster"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"sea urchin"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"sea cucumber"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"My favorite sea creature is:"</span><span class="pun">,</span><span class="pln"> names</span><span class="pun">[</span><span class="pln">len</span><span class="pun">(</span><span class="pln">names</span><span class="pun">)])</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">panic: runtime error: index out of range [3] with length 3

goroutine 1 [running]:
main.main()
    /tmp/sandbox879828148/prog.go:13 +0x20
</pre>

<p>
	لاحظ أننا حصلنا على تلميح <code>panic: runtime error: index out of range</code> والذي يشير إلى أننا نحاول الوصول إلى فهرس خارج حدود المصفوفة.
</p>

<p>
	أنشأنا شريحة <code>names</code> بثلاث قيم ثم حاولنا طباعة العنصر الأخير من خلال القيمة المُعادة من الدالة <code>()len</code> والتي ستُعيد القيمة 3، لكن آخر عنصر في المصفوفة يملك الفهرس 2 وليس 3 بما أنّ الفهرسة تبدأ من الصفر وليس من الواحد، لذا في هذه الحالة لا يوجد خيارًا لوقت التشغيل إلا أن يتوقف ويُنهي البرنامج، أيضًا لا يمكن لجو أن تُبرهِن أثناء عملية التصريف أن الشيفرة ستحاول فعل ذلك، لذلك لا يمكن للمُصرِّف التقاط هذا.
</p>

<p>
	تُسبب حالة الانهيار إيقاف تنفيذ برنامجك تمامًا، وبالتالي لن تُنفّذ أيّة تعليمات برمجية تالية، كما تحتوي الرسالة الناتجة على العديد من المعلومات المفيدة في تشخيص سبب حالة الانهيار.
</p>

<h2>
	مكونات حالة الانهيار
</h2>

<p>
	تتكون حالات الانهيار من رسالة تحاول توضيح سبب حالة الانهيار إضافةً إلى مسار المكدس stack trace الذي يساعدك على تحديد مكان حدوث حالة الانهيار في تعليماتك البرمجية، إذ تبدأ رسالة الانهيار بالكلمة <code>panic:‎</code> تتبعها <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">سلسلة نصية</a> توضيحية تختلف تبعًا لسبب حالة الانهيار، فرسالة الانهيار في المثال السابق كانت كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_20" style=""><span class="pln">panic</span><span class="pun">:</span><span class="pln"> runtime error</span><span class="pun">:</span><span class="pln"> index out of range </span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> with length </span><span class="lit">3</span></pre>

<p>
	تخبرنا السلسلة <code>runtime error:‎</code> التي تتبع الكلمة <code>panic:‎</code> أنّ الخطأ قد حدث في وقت التشغيل؛ أما بقية الرسالة، فتخبرنا بأن الفهرس 3 خارج حدود الشريحة.
</p>

<p>
	الرسالة التالية هي رسالة مسار المكدس، وهي خريطة يمكننا تتبُعها لتحديد سطر التعليمات البرمجية الذي أدى تنفيذه إلى حدوث حالة الانهيار وكيفية استدعاء هذه الشيفرة من شيفرة أخرى.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_22" style=""><span class="pln">goroutine </span><span class="lit">1</span><span class="pln"> </span><span class="pun">[</span><span class="pln">running</span><span class="pun">]:</span><span class="pln">
main</span><span class="pun">.</span><span class="pln">main</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">/</span><span class="pln">tmp</span><span class="pun">/</span><span class="pln">sandbox879828148</span><span class="pun">/</span><span class="pln">prog</span><span class="pun">.</span><span class="pln">go</span><span class="pun">:</span><span class="lit">13</span><span class="pln"> </span><span class="pun">+</span><span class="lit">0x20</span></pre>

<p>
	يوضّح مسار المكدس هذا أن حالة الانهيار قد حدثت في الملف ‎/tmp/sandbox879828148/prog.go في السطر رقم 13، كما يخبرنا أيضًا أنه نشأ في الدالة <code>()main</code> من الحزمة الرئيسية <code>main</code>.
</p>

<p>
	ينقسم مسار المكدس إلى عدة أقسام بحيث يكون هناك قسم لكل روتين <code>goroutine</code> فكل عملية تنفيذ لبرنامج في جو تُنجز من خلال روتين واحد أو أكثر، أي كل روتين يُنفذ جزء محدد من الشيفرة، وكل من هذه الروتينات يُمكن تنفيذها باستقلالية عن باقي الروتينات وبالتزامن معها.
</p>

<p>
	تبدأ كل كتلة بالرأس <code>:[goroutine X [state</code>، تُمثّل الإشارة <code>X</code> إلى رقم الروتين ID (مُعرّفه) مع الحالة التي كان عليها عندما حدثت حالة الانهيار، ويعرض مسار المكدس بعد الرأس الدالة التي حدثت فيها حالة الانهيار أثناء تنفيذها إلى جانب اسم الملف ورقم سطر تنفيذ الدالة.
</p>

<h2>
	الإشارة إلى العدم
</h2>

<p>
	يمكن أن تحدث حالة الانهيار أيضًا عند محاولة استدعاء تابع على مؤشر لا يُشير إلى أيّ شيء، إذ تُمكننا المؤشرات في جو من الإشارة إلى نسخ مُحددة من بعض الأنواع الموجودة في الذاكرة خلال وقت التشغيل، وعندما لا يُشير المؤشر إلى أيّ شيء، فستكون قيمة المؤشر <code>nil</code>، وعندما نحاول استدعاء توابع على مؤشر لا يشير إلى شيء، فستظهر حالة انهيار، والأمر ذاته بالنسبة للمتغيرات التي تكون من أنواع الواجهات، إذ تولّد أيضًا حالة الانهيار إذا استُدعيت توابع عليها كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_24" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">Shark</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln"> string
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">s </span><span class="pun">*</span><span class="typ">Shark</span><span class="pun">)</span><span class="pln"> </span><span class="typ">SayHello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Hi! My name is"</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">.</span><span class="typ">Name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    s </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Shark</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">}</span><span class="pln">
    s </span><span class="pun">=</span><span class="pln"> nil
    s</span><span class="pun">.</span><span class="typ">SayHello</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xdfeba]

goroutine 1 [running]:
main.(*Shark).SayHello(...)
    /tmp/sandbox160713813/prog.go:12
main.main()
    /tmp/sandbox160713813/prog.go:18 +0x1a
</pre>

<p>
	عرّفنا في هذا المثال سجل <code>struct</code> اسميناه <code>Shark</code> يحتوي على تابع وحيد مُعرَّف ضمن مُستقبل مؤشرها واسمه <code>SayHello</code> والذي يطبع تحية عند استدعائه، كما نُنشئ داخل جسم الدالة <code>main</code> نسخةً جديدةً من السجل <code>Shark</code> ونحاول أخذ مؤشر عليها باستخدام العامِل <code>&amp;</code>، إذ يُسنَد المؤشر إلى المتغير <code>s</code> ثم نُسند المتغير <code>s</code> مرةً أخرى إلى القيمة <code>nil</code> من خلال التعليمة <code>s = nil</code> ثم نحاول استدعاء التابع <code>SayHello</code> على المتغير<code>s</code>.
</p>

<p>
	نتيجةً لذلك نحصل على حالة انهيار تُشير إلى محاولة الوصول إلى عنوان ذاكرة غير صالح لأن المتغير <code>s</code> كانت قيمته <code>nil</code>، وبالتالي عند استدعاء الدالة <code>SayHello</code> فإنه يحاول الوصول إلى الحقل <code>Name</code> الموجود على النوع <code>‎*Shark</code>، وبالتالي تحدث حالة انهيار لأنه لا يمكن تحصيل dereference قيمة غير موجودة <code>nil</code> بما أنّ المؤشر هو مؤشر استقبال والمستقبل في هذه الحالة هو <code>nil</code>.
</p>

<p>
	حددنا في هذا المثال القيمة <code>nil</code> صراحةً، لكن تظهر هذه القيم في الحالات العملية من دون انتباهنا، إذًا، عندما تظهر لديك حالات انهيار تتضمن الرسالة <code>nil pointer dereference</code>، ينبغي عليك التحقق مما إذا كنت تُسند قيمة <code>nil</code> إلى أحد المؤشرات التي تستخدِمها في برنامجك.
</p>

<h2>
	استخدام دالة panic المضمنة
</h2>

<p>
	حالات الانهيار الناتجة عن تجاوز حدود الشريحة أو تلك الناتجة عن المؤشرات ذات القيمة <code>nil</code> هي الأشهر، لكن من الممكن أيضًا أن نُظهر حالة انهيار يدويًا من خلال الدالة المُضمّنة <code>panic</code> التي تأخذ وسيط واحد فقط يُمثِّل السلسلة النصية التي ستمثّل رسالة الانهيار، وعادةً ما يكون عرض هذه الرسالة أكثر راحةً من تعديل الشيفرة بحيث تعيد خطأً، كما يمكننا أيضًا استخدامها داخل الحزم الخاصة بنا لتنبيه المطورين إلى أنهم قد ارتكبوا خطأً عند استخدام شيفرة الحزمة خاصتنا، عمومًا، يُفضَّل إعادة قيم الخطأ <code>error</code> إلى مُستخدمِي الحزمة، وسيطلق المثال التالي حالة انهيار ناتجةً عن دالة تُستدعى من دالة أخرى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_26" style=""><span class="pln">package main

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    foo</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    panic</span><span class="pun">(</span><span class="str">"oh no!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستكون حالة الانهيار الناتجة كما يلي:
</p>

<pre class="ipsCode">panic: oh no!

goroutine 1 [running]:
main.foo(...)
    /tmp/sandbox494710869/prog.go:8
main.main()
    /tmp/sandbox494710869/prog.go:4 +0x40
</pre>

<p>
	عرّفنا في هذا المثال الدالة <code>foo</code> التي تستدعي الدالة <code>panic</code> والتي نُمرر لها السلسلة "oh no!‎" ثم استدعينا هذه الدالة <code>foo</code> من داخل الدالة <code>main</code>.
</p>

<p>
	لاحظ أنّ الخرج يتضمن الرسالة التي حددناها للدالة <code>panic</code> ويعرض مسار المكدس لنا روتينًا واحدًا وسطرين من المسارات؛ الأول للدالة <code>()main</code> والثاني للدالة <code>()foo</code>.
</p>

<p>
	وجدنا مما سبق أنّ حالات الانهيار تؤدي إلى إنهاء البرنامج لحظة حدوثها، ويمكن أن يؤدي ذلك إلى حدوث مشكلات عند وجود موارد مفتوحة يجب إغلاقها بطريقة سليمة، وهنا توفِّر جو آليةً لتنفيذ بعض التعليمات البرمجية دائمًا حتى عندما تظهر حالة الانهيار.
</p>

<h2>
	الدوال المؤجلة
</h2>

<p>
	قد يحتوي برنامجك على موارد يجب تنظيفها بطريقة سليمة، حتى أثناء معالجة حالات الانهيار في وقت التشغيل، إذ تسمح لك <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">جو</a> بتأجيل تنفيذ استدعاء دالة ريثما تكون الدالة المُستدعاة ضمنها قد أكتمل تنفيذها.
</p>

<p>
	يُمكن للدوال المؤجلة أن تُنفّذ حتى عند ظهور حالة انهيار وتستخدم بوصفها تقنية أمان للحماية من الفوضى والمشكلات التي قد تسببها حالة الانهيار، ولتأجيل دالة نستخدِم الكلمة المفتاحية <code>defer</code> قبل اسم الدالة كما يلي <code>()defer sayHello</code>، ولاحظ في المثال التالي أن الرسالة ستظهر رغم حدوث حالة انهيار:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_29" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer func</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"hello from the deferred function!"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}()</span><span class="pln">

    panic</span><span class="pun">(</span><span class="str">"oh no!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">hello from the deferred function!
panic: oh no!

goroutine 1 [running]:
main.main()
    /Users/gopherguides/learn/src/github.com/gopherguides/learn//handle-panics/src/main.go:10 +0x55
</pre>

<p>
	نؤجل استدعاء دالة مجهولة الاسم داخل الدالة <code>()main</code> والتي تطبع الرسالة "hello from the deferred function!‎" ثم تُطلق الدالة <code>()main</code> حالة انهيار من خلال استدعاء الدالة <code>panic</code>، ونلاحظ من الخرج أنّ الدالة المؤجلة تُنفّذ أولًا وتُطبع الرسالة الخاصة بها، ثم تظهر لنا رسالة حالة الانهيار.
</p>

<p>
	توفر جو لنا أيضًا فرصة منع حالة الانهيار من إنهاء البرنامج من داخل الدوال المؤجلة من خلال دالة مُضمّنة أخرى.
</p>

<h2>
	معالجة حالات الانهيار
</h2>

<p>
	تمتلك جو تقنية معالجة واحدة تتجسّد في الدالة <code>recover</code>، إذ تسمح لك هذه الدالة في اعتراض حالة الانهيار من مسار المكدس ومنع الإنهاء المُفاجئ للبرنامج.
</p>

<p>
	هناك قواعد صارمة عند التعامل معها، لكنها دالة لا تقُدّر بثمن في تطبيقات الإنتاج، ويمكن استدعاء الدالة <code>recover</code> مباشرةً دون الحاجة إلى استيراد أيّ حزمة لأنها دالة مُضمّنة كما ذكرنا.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_31" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    divideByZero</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"we survived dividing by zero!"</span><span class="pun">)</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

func divideByZero</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer func</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> recover</span><span class="pun">();</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            log</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"panic occurred:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">divide</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func divide</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">2009/11/10 23:00:00 panic occurred: runtime error: integer divide by zero
we survived dividing by zero!
</pre>

<p>
	تُستدعى الدالة <code>divideByZero</code> من داخل الدالة <code>main</code>، كما داخل هذه الدالة نؤجل استدعاء دالة مجهولة الاسم ومسؤولة عن التعامل مع أيّ حالات انهيار قد تنشأ أثناء تنفيذ <code>divideByZero</code>، ونستدعي داخل هذه الدالة مجهولة الاسم الدالة المُضمّنة <code>recover</code> ونسند الخطأ الذي تُعيده إلى المتغير <code>err</code>.
</p>

<p>
	إذا ظهرت حالة انهيار في الدالة <code>()divideByZero</code>، فستُهيّأ قيمة هذا الخطأ، وإلا فستكون <code>nil</code>، ومن خلال مقارنة قيمة المتغير <code>err</code> بالقيمة <code>nil</code>، سنستطيع تحديد فيما إذا كانت حالة الانهيار قد حدثت، وفي هذه الحالة نسجّل حالة الانهيار من خلال الدالة <code>log.Println</code> كما لو كانت أيّ خطأ آخر.
</p>

<p>
	نلاحظ أننا نستدعي الدالة <code>divide</code> ونحاول طباعة ناتجها باستخدام الدالة <code>()fmt.Println</code> بتتبع الدالة المؤجلة مجهولة الاسم بما أن وسيط هذه الدالة سيُسبب القسمة على صفر، وبالتالي ستظهر حالة انهيار.
</p>

<p>
	يُظهر خرج البرنامج رسالة الدالة <code>()log.println</code> من الدالة مجهولة الاسم والتي تُعالج حالة الانهيار متبوعة برسالة <code>we survived dividing by zero!‎</code>، والتي تُشير إلى أننا منعنا حالة الانهيار من إيقاف البرنامج، وذلك بفضل استخدام دالة المعالجة <code>recover</code>.
</p>

<p>
	قيمة الخطأ <code>err</code> المُعادة من الدالة <code>()recover</code> هي نفسها القيمة المُعطاة لاستدعاء الدالة <code>()panic</code>، لذا من المهم التأكد مما إذا كانت قيمتها <code>nil</code>.
</p>

<h2>
	اكتشاف حالات الانهيار باستخدام recover
</h2>

<p>
	تعتمد الدالة <code>recover</code> على قيمة الخطأ في اكتشاف حدوث حالات الانهيار، وبما أن وسيط الدالة <code>panic</code> هو واجهة فارغة، لذا يمكن أن تكون من أي نوع، كما أنّ القيمة الصفرية لأي نوع بيانات يُمثّل واجهةً هو <code>nil</code>، ويوضِّح المثال التالي أنه يجب تجنب تمرير القيمة <code>nil</code> على أساس وسيط للدالة <code>panic</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_740_33" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    divideByZero</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"we survived dividing by zero!"</span><span class="pun">)</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

func divideByZero</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    defer func</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> recover</span><span class="pun">();</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            log</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"panic occurred:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">divide</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func divide</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b </span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> b </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        panic</span><span class="pun">(</span><span class="pln">nil</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">we survived dividing by zero!
</pre>

<p>
	هذا المثال هو المثال السابق نفسه مُتضمنًا الدالة <code>recover</code> مع بعض التعديلات الطفيفة، إذ عدّلنا دالة القسمة للتحقق مما إذا كان المقسوم عليه <code>b</code> يساوي 0، فإذا كان كذلك، فسيولّد حالة انهيار باستخدام الدالة <code>panic</code> مع وسيط من القيمة <code>nil</code>.
</p>

<p>
	لن يتضمن الخرج في هذه المرة رسالة الدالة <code>log</code> التي تعرض حدوث حالة الانهيار بالرغم من حدوث حالة انهيار نتيجة القسمة، ويؤكد هذا السلوك الصامت أهمية التحقق من قيمة الخطأ فيما إذا كانت <code>nil</code>.
</p>

<h2>
	الخاتمة
</h2>

<p>
	رأينا العديد من الطرق التي تؤدي إلى ظهور حالات انهيار في البرنامج، كما أننا عرضنا طرقًا لإنشائها يدويًا، ثم راجعنا الدالة المضمنة <code>recover</code> التي تُمكّننا من معالجة حالات الانهيار، وليس من الضروري أن تحتاج إلى التعامل مع حالات الانهيار في برامجك، لكن عندما يتعلق الأمر بتطبيقات الإنتاج فهي بغاية الأهمية.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/handling-panics-in-go" rel="external nofollow">Handling Panics inGo</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/" rel="">معالجة الأخطاء في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/3-%D8%B7%D8%B1%D8%A7%D8%A6%D9%82-%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-go-r839/" rel="">3 طرائق لنسخ الملفات في Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/" rel="">التعرف على الروابط Maps في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-boolean-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1847/" rel="">البيانات المنطقية Boolean في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1845/" rel="">تحويل أنواع البيانات في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1901</guid><pubDate>Tue, 14 Feb 2023 16:00:00 +0000</pubDate></item><item><title>&#x645;&#x639;&#x627;&#x644;&#x62C;&#x629; &#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1891/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/1085596994_17--------Go.png.23e4c01a21109c19fca09d9a8d33cef6.png" /></p>
<p>
	تتصف البرامج التي تتسم بالمتانة بأنها قادرة على التعامل مع الأخطاء المتوقعة وغير المتوقعة التي قد تحدث عند استخدام البرنامج، فهناك أخطاء ناتجة عن مدخلات غير صحيحة من المستخدِم أو حدوث خطأ في عملية الاتصال بالشبكة، …إلخ.
</p>

<p>
	نقصد بمعالجة الأخطاء Error handling التقاط الأخطاء التي تولّدها برامجنا وإخفائها عن المستخدم، فرسائل الأخطاء لا تخيف المبرمجين وإنما يمكن توقعها أحيانًا، إلا أن المستخدِم لا يتوقع رؤيتها وهي تربكه وتسبب له الحيرة، فإن كان سيرى رسالة خطأ للضرورة، فلتكن رسالةً سهلة الفهم، وحتى في هذه الحالة سيرغب المستخدِم في أن يحل المبرمج المشكلة، وهنا يأتي دور التعامل مع الأخطاء ومعالجتها، إذ توفِّر كل لغة تقريبًا آليةً لالتقاط الأخطاء عند حدوثها لمعرفة الأجزاء التي تعطلت واتخاذ الإجراء المناسب لإصلاح المشكلة.
</p>

<p>
	لمعالجة الأخطاء في <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> الأخرى، عادةً ما يتطلب الأمر من المُبرمجين استخدام بنية قواعد محدَّدة، إلا أنّ الأمر مُختلف في جو، إذ تُعَدّ <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">الأخطاء</a> قيمًا مع نوع الخطأ الذي يُعاد من الدالة مثل أيّ قيمة معادة أخرى، ولمعالجة الأخطاء في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a>، يجب عليك فحص هذه الأخطاء التي قد تُعيدها الدوال وتحديد ما إذا كان هناك خطأ فعلًا، واتخاذ الإجراء المناسب لحماية البيانات وإخبار المستخدِمين أو أجزاء البرنامج الأخرى بحدوث الخطأ.
</p>

<h2>
	إنشاء الأخطاء
</h2>

<p>
	قبل أن تبدأ بمعالجة الأخطاء عليك إنشاؤها أولًا، إذ توفر المكتبة القياسية دالتين مضمنتين لإنشاء أخطاء وهما <code>()errors.New</code> و <code>()fmt.Errorf</code>بحيث تتيح لك هاتان الدالتان تحديد رسالة خطأ مخصصة يمكنك تقديمها لاحقًا للمستخدِمين.
</p>

<p>
	تأخذ الدالة <code>()errors.New</code> وسيطًا واحدًا يمثِّل سلسلةً تُمثّل رسالة الخطأ، بحيث يمكنك تخصيصها لتنبيه المستخدِمين بالخطأ، وسنستخدِم في المثال التالي الدالة <code>()errors.New</code> لإنشاء خطأ وستكون رسالة الخطأ هي "barnacles" ثم سنطبع هذا الخطأ من خلال الدالة <code>()fmt.Println</code>، ولاحظ أننا كتبنا جميع أحرف الرسالة بدون استخدام محارف كبيرة تقيّدًا بالطريقة التي تكتب بها الأخطاء في جو والتي تُكتب بمحارف صغيرة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_9" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"barnacles"</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy says:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">Sammy says: barnacles
</pre>

<p>
	تسمح لك الدالة <code>()fmt.Errorf</code> بإنشاء رسالة خطأ ديناميكيًا، بحيث يمثِّل الوسيط الأول لهذه الدالة سلسلةً تمثِّل رسالة الخطأ مع إمكانية استخدام العناصر النائبة مثل العنصر <code>s%</code> لينوب عن سلسلة نصية والعنصر <code>d%</code> لينوب عن عدد صحيح؛ أما الوسيط الثاني لهذه الدالة، فهو قيم العناصر النائبة بالترتيب كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_11" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"time"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Errorf</span><span class="pun">(</span><span class="str">"error occurred at: %v"</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">())</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"An error happened:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">An error happened: Error occurred at: 2019-07-11 16:52:42.532621 -0400 EDT m=+0.000137103
</pre>

<p>
	استخدمنا الدالة <code>()fmt.Errorf</code> لإنشاء رسالة خطأ تتضمن التوقيت الزمني الحالي، إذ تتضمن السلسلة المُعطاة إلى الدالة <code>()fmt.Errorf</code> العنصر النائب <code>v%</code> والذي سيأخذ القيمة <code>()time.Now</code> لاحقًا عند استدعاء هذا الخطأ، وأخيرًا نطبع الخطأ من خلال دالة الطباعة كما فعلنا مع الدالة السابقة.
</p>

<h2>
	معالجة الأخطاء
</h2>

<p>
	ما سبق كان مُجرّد مثال لتوضيح كيفية إنشاء الأخطاء؛ أما الآن فستتعلم كيفية إنشائها وتوظيفها، فمن الناحية العملية، يكون من الشائع جدًا إنشاء خطأ وإعادته من دالة عندما يحدث خطأ ما، وبالتالي عند استدعاء هذه الدالة يمكن استخدام عبارة <code>if</code> لمعرفة ما إذا كان الخطأ موجودًا أم أنه لايوجد خطأ، فعندما لا يكون هناك خطأً سنجعل الدالة تعيد قيمة <code>nil</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_13" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func boom</span><span class="pun">()</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"barnacles"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> boom</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"An error occurred:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Anchors away!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">An error occurred: barnacles
</pre>

<p>
	عرّفنا في هذا المثال دالة تُسمى <code>boom()‎</code> تُعيد خطأً يُنشأ من خلال الدالة <code>errors.New</code> لاحقًا عند استدعاء هذه الدالة والتقاط الخطأ في السطر <code>err := boom</code>، فبعد إسناد الخطأ إلى المتغير <code>err</code> سنتحقق مما إذا كان موجودًا من خلال التعليمة <code>if err != nil</code>، وفي هذا المثال ستكون نتيجة الشرط دومًا <code>true</code> لأننا نُعيد دومًا خطأً من الدالة، وطبعًا لن يكون الأمر دائمًا هكذا، لذلك يجب أن نحدد في الدالة الحالات التي يحدث فيها خطأ والحالات التي لا يحدث فيها خطأ وتكون القيمة المعادة <code>nil</code>.
</p>

<p>
	نستخدِم دالة الطباعة <code>()fmt.Println</code> لطباعة الخطأ كما في كل مرة عند وجود خطأ، ثم نستخدِم أخيرًا تعليمة <code>return</code> لكي لا تُنفّذ تعليمة <code>("fmt.Println("Anchors away!‎</code>، فهذه التعليمة يجب أن تُنفّذ فقط عند عدم وجود خطأ.
</p>

<p>
	<strong>ملاحظة</strong>: تُعَدّ التعليمة <code>if err != nil</code> محورًا أساسيًا في عملية معالجة الأخطاء، فهي تنقل البرنامج إلى مسار مختلف عن مساره الأساسي في حال وجود خطأ أو تتركه يكمل مساره الطبيعي.
</p>

<p>
	تتيح لك جو إمكانية استدعاء الدالة ومعالجة أخطاءها ضمن تعليمة الشرط <code>if</code> مباشرةً، ففي المثال التالي سنكتب المثال السابق نفسه لكن من خلال الاستفادة من هذه السمة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_16" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func boom</span><span class="pun">()</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"barnacles"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> boom</span><span class="pun">();</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"An error occurred:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Anchors away!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">An error occurred: barnacles
</pre>

<p>
	لاحظ أننا لم نغير كثيرًا عن الشيفرة السابقة، فكل ما فعلناه هو أننا استدعينا الدالة التي تُعيد الخطأ واختبرنا الشرط في السطر نفسه ضمن التعليمة <code>if</code>.
</p>

<p>
	تعلمنا في هذا القسم كيفية التعامل مع الدوال التي تعيد الخطأ فقط، وهذه الدوال شائعة، لكن من المهم أيضًا أن تكون قادرًا على معالجة الأخطاء من الدوال التي يمكن أن تُعيد قيمًا متعددةً.
</p>

<h2>
	إعادة الأخطاء والقيم
</h2>

<p>
	غالبًا ما تُستخدَم الدالات التي تُعيد قيمة خطأ واحدة في الحالات التي نحتاج فيها إلى إحداث تغييرات مُحددة مثل إدراج صفوف في <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة بيانات</a> أي عندما نحتاج لمعرفة الحال الذي انتهت عليه العملية، ومن الشائع أيضًا كتابة دالات تُعيد قيمة إذا اكتملت العملية بنجاح أو خطأ مُحتمل إذا فشلت هذه العملية، كما تسمح جو للدالات بإعادة أكثر من نتيجة واحدة، وبالتالي إمكانية إعادة قيمة ونوع الخطأ في الوقت نفسه.
</p>

<p>
	لإنشاء دالة تُعيد أكثر من قيمة واحدة، يجب تحديد أنواع كل قيمة مُعادة داخل أقواس ضمن ترويسة الدالة، فالدالة <code>capitalize</code> مثلًا، تُعيد سلسلة <code>string</code> وخطأ <code>error</code>، وقد صرّحنا عن ذلك بكتابة شيفرة كتلية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_19" style=""><span class="pln"> func capitalize</span><span class="pun">(</span><span class="pln">name string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	يخبر الجزء (سلسلة، خطأ) مُصرّف جو أنّ هذه الدالة ستعيد سلسلةً نصيةً وخطأً بهذا الترتيب، ويمكنك تشغيل البرنامج التالي لرؤية الخرج من هذه الدالة التي تُعيد قيمتين وهما سلسلة نصية وخطأ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_21" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func capitalize</span><span class="pun">(</span><span class="pln">name string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"no name provided"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">ToTitle</span><span class="pun">(</span><span class="pln">name</span><span class="pun">),</span><span class="pln"> nil
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> capitalize</span><span class="pun">(</span><span class="str">"sammy"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Could not capitalize:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Capitalized name:"</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">Capitalized name: SAMMY
</pre>

<p>
	عرّفنا الدالة <code>()capitalize</code> التي تأخذ <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">سلسلة نصية</a> على أساس وسيط وهي السلسلة التي نريد تحويل محارفها إلى محارف كبيرة، وتُعيد سلسلةً نصيةً وقيمة خطأ.
</p>

<p>
	استدعينا في الدالة الرئيسية <code>()main</code> الدالة <code>()capitalize</code> وأسندنا القيم التي تُعيدها إلى المتغيرين <code>name</code> و <code>err</code> من خلال الفصل بينهما بفاصلة، ثم استخدمنا التعليمة الشرطية <code>if err != nil</code> للتحقق من وجود خطأ والذي سنطبعه في حال وجوده ونخرج من خلال التعليمة <code>return</code> وإلا سنكمل في المسار الطبيعي ونطبع <code>(fmt.Println("Capitalized name:", name</code>.
</p>

<p>
	مرَّرنا في المثال السابق الكلمة <code>sammy</code> للدالة <code>()capitalize</code>، لكن إذا حاولت تمرير سلسلة فارغة <code>""</code>، فستحصل مباشرةً على رسالة الخطأ <code>Could not capitalize: no name provided</code>، أي عند تمرير سلسلة فارغة، ستُعيد الدالة خطأً، وعند تمرير سلسلة عادية، ستستخدِم الدالة <code>()capitalize</code> الدالة <code>strings.ToTitle</code> لتحويل السلسلة الممرَّرة إلى محارف كبيرة ثم تُعيدها، كما تُعيد في هذه الحالة <code>nil</code> أيضًا لإشارة إلى عدم وجود خطأ.
</p>

<p>
	هناك بعض الاصطلاحات الدقيقة التي اتبعها هذا المثال والتي تُعَدّ نموذجيةً في شيفرات جو ولكن ليست إجباريةً من قِبَل مصرِّف جو، فعندما تكون لدينا دالة تُعيد عدة قيم مثلًا، يُشاع أن تكون قيمة الخطأ المُعادة هي القيمة الأخيرة، أيضًا عندما تُعاد قيمة خطأ ما، فستُسنَد القيمة الصفرية إلى كل قيمة لا تمثّل خطأ، والقيم الصفرية مثلًا هي القيمة 0 في حالة الأعداد الصحيحة أو السلسلة الفارغة في حالة السلاسل النصية أو السجل الفارغ في حالة نوع البيانات <code>struct</code> أو القيمة <code>nil</code> في حالة المؤشر والواجهة interface، وقد تحدّثنا عن ذلك سابقًا بالتفصيل في مقال <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">المتغيرات والثوابت</a>.
</p>

<h3>
	تقليل استخدام الشيفرة المتداولة
</h3>

<p>
	يمكن أن يصبح الالتزام بهذه الاصطلاحات مملًا في المواقف التي تكون لدينا فيها العديد من القيم المُعادة من دالة، إذ يمكننا استخدام مفهوم الدالة مجهولة الاسم anonymous function للمساعدة في تقليل الشيفرة المتداولة boilerplate.
</p>

<p>
	تُعَدّ الدوال مجهولة الاسم إجرائيات مسنَدَة إلى المتغيرات، على عكس الدوال التي عرَّفناها في الأمثلة السابقة، فهي متوفرة فقط ضمن الدوال التي تُصرّح عنها، وهذا يجعلها مثاليةً لتعمل على أساس أجزاء منطقية قصيرة مُساعدة وقابلة لإعادة الاستخدام.
</p>

<p>
	سنعدّل المثال السابق بحيث نضيف له طول الاسم الذي نريد تحويل حالة المحارف فيه إلى الحالة الكبيرة، وبما أنه لدينا ثلاث قيم تجب إعادتها، فقد يصبح التعامل مع الأخطاء مرهقًا بدون دالة مجهولة الاسم تُساعدنا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_24" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func capitalize</span><span class="pun">(</span><span class="pln">name string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    handle </span><span class="pun">:=</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">err error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> handle</span><span class="pun">(</span><span class="pln">errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"no name provided"</span><span class="pun">))</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">ToTitle</span><span class="pun">(</span><span class="pln">name</span><span class="pun">),</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">name</span><span class="pun">),</span><span class="pln"> nil
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> capitalize</span><span class="pun">(</span><span class="str">"sammy"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"An error occurred:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Capitalized name: %s, length: %d"</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">Capitalized name: SAMMY, length: 5
</pre>

<p>
	نستقبل 3 وسائط مُعادة من الدالة <code>()capitalize</code> داخل الدالة <code>()main</code>، وهي <code>name</code> و <code>size</code> و <code>err</code> على التوالي، ثم نختبر بعد ذلك فيما إذا كانت الدالة <code>()capitalize</code> قد أعادت خطأً أم لا وذلك من خلال فحص قيمة المتغير <code>err</code> إذا كان <code>nil</code> أم لا، فمن المهم فعل ذلك قبل محاولة استخدام أيّ من القيم الأخرى المُعادة من الدالة <code>capitalize</code> لأن الدالة مجهولة الاسم <code>handle</code> يمكن أن تضبطها على قيم صفرية، وفي هذا المثال لم نُمرِّر سلسلةً فارغةً، لذا أكمل البرنامج عمله وفقًا للمسار الطبيعي، ويمكنك تمرير سلسلة فارغة لترى أنّ الخرج سيكون رسالة خطأ <code>An error occurred: no name provided</code>.
</p>

<p>
	عرّفنا المتغير <code>handle</code> داخل الدالة <code>capitalize</code> وأسندنا إليه دالة مجهولة الاسم، أي أنّ هذا المتغير أصبح يُمثّل دالةً مجهولة الاسم، وستأخذ خطأ <code>error</code> على أساس وسيط وتُعيد قيمًا تُطابق القيم التي تُعيدها الدالة <code>capitalize</code> وبالترتيب نفسه لكن تجعل قيمها صفريّة، كما تُعيد الدالة الخطأ الذي مرِّر لها أيضًا كما هو، وبناءً على ذلك سيكون بإمكاننا إعادة أي أخطاء تحدث في الدالة <code>capitalize</code> باستخدام تعليمة <code>return</code> يليها استدعاء الدالة مجهولة الاسم <code>handle</code> مع تمرير الخطأ على أساس وسيط.
</p>

<p>
	تذكَّر أنّ الدالة <code>capitalize</code> يجب أن تُعيد دومًا ثلاث قيم فهكذا عرّفناها، ولكن في بعض الأحيان لا نريد التعامل مع جميع القيم التي يمكن أن تُعيدها الدالة، لذا لحسن الحظ يمكننا التعامل مع هذا الأمر من خلال استخدام الشَرطة السفلية <code>_</code> كما سترى بعد قليل.
</p>

<h2>
	معالجة الأخطاء في الدوال التي تعيد عدة قيم
</h2>

<p>
	عندما تُعيد الدالة العديد من القيم، ينبغي علينا إسناد كل منها إلى متغير وهذا ما فعلناه في المثال السابق مع الدالة <code>capitalize</code>، كما يجب فصل هذه المتغيرات بفواصل.
</p>

<p>
	لا نحتاج في بعض الأحيان إلا لقيم محددة منها، فقد لا نحتاج مثلًا إلا لقيمة الخطأ <code>error</code>، ففي هذه الحالة يمكنك استخدام الشرطة السفلية <code>_</code> لتجاهل القيم الأُخرى المُعادة، وقد عدّلنا المثال الأول عن الدالة <code>()capitalize</code> في المثال التالي ومرّرنا لها سلسلةً فارغةً لكي تُعطينا خطأً واستخدمنا الشرطة السفلية لتجاهل القيمة الأولى التي تُعيدها الدالة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_26" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func capitalize</span><span class="pun">(</span><span class="pln">name string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> name </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"no name provided"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">ToTitle</span><span class="pun">(</span><span class="pln">name</span><span class="pun">),</span><span class="pln"> nil
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> capitalize</span><span class="pun">(</span><span class="str">""</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Could not capitalize:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Success!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">Could not capitalize: no name provided
</pre>

<p>
	استدعينا الدالة <code>()capitalize</code> في المثال أعلاه داخل الدالة الرئيسية <code>()main</code> وأسندنا القيم المُعادة منها إلى المتغير <code>_</code> والمتغير <code>err</code> على التوالي، وبذلك نكون قد تجاهلنا القيمة الأولى المُعادة من الدالة واحتفظنا بقيمة الخطأ داخل المتغير <code>err</code>، وما تبقى شرحناه سابقًا.
</p>

<h2>
	تعريف أنواع أخطاء جديدة مخصصة
</h2>

<p>
	نحتاج في بعض الأوقات إلى تعريف أنواع أكثر تعقيدًا من الأخطاء من خلال تنفيذ الواجهة <code>error</code>، إذ لا تكفينا دوال المكتبة القياسية <code>()errors.New</code> و <code>()fmt.Errorf</code> في بعض الأحيان لالتقاط ما حدث والإبلاغ عنه بالطريقة المناسبة، لذا تكون البنية التي نحتاج إلى تحقيقها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_28" style=""><span class="pln">type error interface </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Error</span><span class="pun">()</span><span class="pln"> string
</span><span class="pun">}</span></pre>

<p>
	تتضمّن الواجهة <code>error</code> تابعًا وحيدًا هو <code>()Error</code> والذي يُعيد سلسلةً نصيةً تمثّل رسالة خطأ، فبهذا التابع ستتمكن من تعريف الخطأ بالطريقة التي تناسبك، وفي المثال التالي سننفِّذ الواجهة <code>error</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_31" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">MyError</span><span class="pln"> </span><span class="kwd">struct</span><span class="pun">{}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">m </span><span class="pun">*</span><span class="typ">MyError</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"boom"</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func sayHello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">(</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">MyError</span><span class="pun">{}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    s</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> sayHello</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"unexpected error: err:"</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">)</span><span class="pln">
        os</span><span class="pun">.</span><span class="typ">Exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"The string:"</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنرى الخرج التالي:
</p>

<pre class="ipsCode">unexpected error: err: boom
exit status 1
</pre>

<p>
	عرّفنا نوع بيانات عبارة عن سجل <code>struct</code> فارغ واسميناه <code>MyError</code>، كما عرّفنا التابع <code>()Error</code> داخله بحيث يُعيد الرسالة <code>"boom"</code>.
</p>

<p>
	نستدعي الدالة <code>sayHello</code> داخل الدالة الرئيسية <code>()main</code> التي تُعيد سلسلةً فارغةً ونسخةً جديدةً من <code>MyError</code>، وبما أنّ <code>sayHello</code> ستُعطي خطأً دومًا، فسيُنفَّذ استدعاء <code>()fmt.Println</code> الموجود داخل التعليمة الشرطية دومًا وستُطبع رسالة الخطأ.
</p>

<p>
	لاحظ أنه لا نحتاج إلى استدعاء التابع <code>()Error</code> مُباشرةً لأن الحزمة <code>fmt</code> قادرة تلقائيًا على اكتشاف أنّ هذا تنفيذ للواجهة <code>error</code>، وبالتالي يُستدعى التابع <code>()Error</code> تلقائيًّا وتُطبع رسالة الخطأ.
</p>

<h2>
	الحصول على معلومات تفصيلية عن خطأ
</h2>

<p>
	يكون الخطأ المخصص custom error عادةً هو أفضل طريقة لالتقاط معلومات تفصيلية عن خطأ، فلنفترض مثلًا أننا نريد التقاط رمز الحالة status code عند حدوث أخطاء ناتجة عن طلب <code><a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">HTTP</a></code>، لذا سننفِّذ الواجهة <code>error</code> في البرنامج التالي بحيث يمكننا التقاط هكذا معلومات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_34" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">RequestError</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">StatusCode</span><span class="pln"> </span><span class="typ">int</span><span class="pln">

    </span><span class="typ">Err</span><span class="pln"> error
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">r </span><span class="pun">*</span><span class="typ">RequestError</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="str">"status %d: err %v"</span><span class="pun">,</span><span class="pln"> r</span><span class="pun">.</span><span class="typ">StatusCode</span><span class="pun">,</span><span class="pln"> r</span><span class="pun">.</span><span class="typ">Err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func doRequest</span><span class="pun">()</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">RequestError</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">StatusCode</span><span class="pun">:</span><span class="pln"> </span><span class="lit">503</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Err</span><span class="pun">:</span><span class="pln">        errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"unavailable"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> doRequest</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
        os</span><span class="pun">.</span><span class="typ">Exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"success!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنرى الخرج التالي:
</p>

<pre class="ipsCode">status 503: err unavailable
exit status 1
</pre>

<p>
	أنشأنا في هذا المثال نسخةً من <code>RequestError</code> وزوّدناها برمز الحالة والخطأ باستخدام الدالة <code>errors.New</code> من المكتبة القياسية، ثم نستخدِم بعد ذلك الدالة <code>()fmt.Println</code> لطباعتها كما هو الحال في الأمثلة السابقة. استخدمنا الدالة <code>()fmt.Sprintf</code> داخل التابع <code>()Error</code> في <code>RequestError</code> لإنشاء سلسلة باستخدام المعلومات المقدَّمة عند إنشاء الخطأ.
</p>

<h2>
	توكيدات النوع والأخطاء المخصصة
</h2>

<p>
	تعرض الواجهة <code>error</code> دالةً واحدةً فقط، لكن قد نحتاج إلى الوصول إلى دوال أخرى من تنفيذات أخرى للواجهة <code>error</code> لمعالجة الخطأ بطريقة مناسبة، فقد يكون لدينا مثلًا العديد من التنفيذات للواجهة <code>error</code> والتي تكون مؤقتةً ويمكن إعادة طلبها، إذ يُشار إليها بوجود التابع <code>()Temporary</code>.
</p>

<p>
	توفِّر الواجهات رؤيةً ضيقةً لمجموعة أوسع من التوابع التي يمكن للأنواع أن توفرها، لذلك يجب علينا تطبيق عملية توكيد النوع type assertion لتغيير التوابع التي تُعرض أو إزالتها بالكامل، ويوسِّع المثال التالي النوع <code>RequestError</code> بتضمينه التابع <code>()Temporary</code> والذي سيشير إذا كان يجب على من يستدعي الدالة إعادة محاولة الطلب أم لا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_36" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"net/http"</span><span class="pln">
    </span><span class="str">"os"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">RequestError</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">StatusCode</span><span class="pln"> </span><span class="typ">int</span><span class="pln">

    </span><span class="typ">Err</span><span class="pln"> error
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">r </span><span class="pun">*</span><span class="typ">RequestError</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> r</span><span class="pun">.</span><span class="typ">Err</span><span class="pun">.</span><span class="typ">Error</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">r </span><span class="pun">*</span><span class="typ">RequestError</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Temporary</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> r</span><span class="pun">.</span><span class="typ">StatusCode</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">StatusServiceUnavailable</span><span class="pln"> </span><span class="com">// 503</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func doRequest</span><span class="pun">()</span><span class="pln"> error </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">RequestError</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">StatusCode</span><span class="pun">:</span><span class="pln"> </span><span class="lit">503</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Err</span><span class="pun">:</span><span class="pln">        errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"unavailable"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> doRequest</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
        re</span><span class="pun">,</span><span class="pln"> ok </span><span class="pun">:=</span><span class="pln"> err</span><span class="pun">.(*</span><span class="typ">RequestError</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> ok </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> re</span><span class="pun">.</span><span class="typ">Temporary</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"This request can be tried again"</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"This request cannot be tried again"</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        os</span><span class="pun">.</span><span class="typ">Exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"success!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">unavailable
This request can be tried again
exit status 1
</pre>

<p>
	نستدعي الدالة <code>()doRequest</code> ضمن الدالة <code>main</code> التي تُعيد لنا الواجهة <code>error</code>، إذ نطبع أولًا رسالة الخطأ المُعادة من التابع <code>()Error</code> ثم نحاول كشف جميع التوابع من <code>()RequestError</code> باستخدام توكيد النوع <code>(re, ok := err.(*RequestError</code>، فإذا نجح توكيد النوع، فإننا سنستخدِم التابع <code>()Temporary</code> لمعرفة ما إذا كان هذا الخطأ خطأً مؤقتًا.
</p>

<p>
	بما أنّ المتغير <code>StatusCode</code> الذي هُيئ من خلال الدالة <code>()doRequest</code> يحمل القيمة 503 والذي يتطابق مع <code>http.StatusServiceUnavailable</code>، فإنّ ذلك يُعيد <code>true</code> وبالتالي طباعة <code>"This request can be tried again"</code>، كما يمكننا من الناحية العملية تقديم طلب آخر بدلًا من طباعة رسالة.
</p>

<h2>
	تغليف الأخطاء
</h2>

<p>
	سيكون منشأ الخطأ غالبًا خارجيًا أي من خارج برنامجك مثل قاعدة بيانات واتصال بالشبكة ومدخلات مستخدِم غير صحيحة، …إلخ، فرسائل الخطأ المقدَّمة من هذه الأخطاء لا تساعد أيّ شخص في العثور على أصل الخطأ.
</p>

<p>
	سيُقدِّم تغليف الأخطاء بمعلومات إضافية في بداية رسالة الخطأ رؤيةً أفضل (معلومات عن السياق أو الطبيعة التي حدث فيها) لتصحيح الأخطاء بنجاح، ويوضِّح المثال التالي كيف يمكننا إرفاق بعض المعلومات السياقية لخطأ خفي من دالة أخرى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9931_38" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"errors"</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

type </span><span class="typ">WrappedError</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Context</span><span class="pln"> string
    </span><span class="typ">Err</span><span class="pln">     error
</span><span class="pun">}</span><span class="pln">

func </span><span class="pun">(</span><span class="pln">w </span><span class="pun">*</span><span class="typ">WrappedError</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">()</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="str">"%s: %v"</span><span class="pun">,</span><span class="pln"> w</span><span class="pun">.</span><span class="typ">Context</span><span class="pun">,</span><span class="pln"> w</span><span class="pun">.</span><span class="typ">Err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func </span><span class="typ">Wrap</span><span class="pun">(</span><span class="pln">err error</span><span class="pun">,</span><span class="pln"> info string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="typ">WrappedError</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">WrappedError</span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Context</span><span class="pun">:</span><span class="pln"> info</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Err</span><span class="pun">:</span><span class="pln">     err</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    err </span><span class="pun">:=</span><span class="pln"> errors</span><span class="pun">.</span><span class="typ">New</span><span class="pun">(</span><span class="str">"boom!"</span><span class="pun">)</span><span class="pln">
    err </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Wrap</span><span class="pun">(</span><span class="pln">err</span><span class="pun">,</span><span class="pln"> </span><span class="str">"main"</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode">main: boom!
</pre>

<p>
	يحتوي السجل <code>WrappedError</code> على حقلين هما رسالة عن السياق على هيئة سلسلة نصية والخطأ الذي يقدِّم عنه معلومات إضافيةً، فعندما يُستدعى التابع <code>()Error</code>، فإننا نستخدِم <code>()fmt.Sprintf</code> مرةً أخرى لطباعة رسالة السياق ثم الخطأ، إذ يستدعي <code>()fmt.Sprintf</code> التابع <code>()Error</code> ضمنيًا.
</p>

<p>
	نستدعي الدالة <code>errors.New</code> داخل الدالة <code>()main</code> ثم نغلِّف الخطأ باستخدام الدالة <code>Wrap</code> التي عرّفناها، إذ يسمح لنا ذلك بالإشارة إلى أنّ هذا الخطأ قد أُنشئ في الدالة <code>main</code>، وبما أنّ <code>WrappedError</code> هي خطأ، لذا يمكننا تغليف العديد منها، إذ يسمح لنا ذلك بالحصول على سلسلة تمكننا من تتبع مصدر الخطأ، كما يمكننا أيضًا تضمين كامل مسار المكدس في الأخطاء التي تحدث مع القليل من المساعدة من المكتبة القياسية.
</p>

<p>
	بما أن الواجهة <code>error</code> لا تحتوي إلا تابعًا واحدًا، فسيمنحنا ذلك مرونةً كبيرةً في تقديم أنواع مختلفة من الأخطاء لمواقف مختلفة، ويمكن أن يشمل ذلك كل شيء بدءًا من وصل أجزاء متعددة من المعلومات على أساس جزء من الخطأ الأساسي وصولًا إلى تحقيق التراجع الأسي Exponential backoff.
</p>

<h2>
	الخاتمة
</h2>

<p>
	رأينا في هذا المقال العديد من الطرق لإنشاء الأخطاء باستخدام المكتبة القياسية وكيفية إنشاء دوال تُعيد الأخطاء بطريقة اصطلاحية، وتمكَّنا أيضًا من إنشاء العديد من الأخطاء بنجاح باستخدام دوال المكتبة القياسية <code>()errors.New</code> و <code>()fmt.Errorf</code>، كما تعلّمت أيضًا كيفية إنشاء أنواع أخطاء مُخصصة وكيفية تتبع الأخطاء التي تحدث في البرنامج من خلال تغليفها.
</p>

<p>
	وبطبيعة الحال، الأخطاء البرمجية موجودة وشائعة في مجال البرمجة ولغات البرمجة عمومًا، لذا من أجل التعرف على الأخطاء البرمجية عامةً والتعرف على كيفية التعامل معها، ندعوك لمشاهدة الفيديو الأتي:
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" src="https://academy.hsoub.com/applications/core/interface/index.html" title="كيفية التعامل مع الأخطاء البرمجية" width="1072" data-embed-src="https://www.youtube.com/embed/Pgje6nWuDkg"></iframe>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/handling-errors-in-go" rel="external nofollow">Handling Errors in Go</a> وللمقال <a href="https://www.digitalocean.com/community/tutorials/creating-custom-errors-in-go" rel="external nofollow">Creating Custom Errors in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D8%AC%D9%88-go-r1866/" rel="">المصفوفات Arrays والشرائح Slices في جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">كيفية التعامل مع الأخطاء البرمجية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%B3%D8%A8%D8%B9-%D8%A7%D9%84%D9%82%D8%A7%D8%AA%D9%84%D8%A9-%D9%84%D8%A3%D9%8A%D9%91-%D9%85%D8%B4%D8%B1%D9%88%D8%B9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA-r742/" rel="">الأخطاء السبع القاتلة لأي مشروع برمجيات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1891</guid><pubDate>Tue, 07 Feb 2023 16:09:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#x627;&#x62A; Arrays &#x648;&#x627;&#x644;&#x634;&#x631;&#x627;&#x626;&#x62D; Slices &#x641;&#x64A; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D8%AC%D9%88-go-r1866/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1394686740_16-------Go.png.0ca261dc99bc5f98a974f2f1d0659016.png" /></p>
<p>
	تُعَدّ المصفوفات Arrays والشرائح Slices في لغة جو بُنى بيانات تتألف من تسلسل مرتب من العناصر، وتكون هذه الأنواع من بُنى المعطيات ذات فائدة كبيرة عندما تعمل مع مجموعة من القيم التي ترتبط مع بعضها البعض بطريقة ما، كما أنها تسمح لك بالاحتفاظ بالبيانات المتشابهة أو ذات الصلة ببعضها معًا وتنفيذ العديد من العمليات عليها كلها أو على مجموعات جزئية منها ودفعةً واحدةً.
</p>

<p>
	تتسم المصفوفات في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> بأنها ثابتة الحجم، أي لن يكون بإمكانك تغيير ذلك بعد تحديد حجمها لأول مرة، فإذا صرّحت مثلًا عن مصفوفة <code>a</code> بعدد عناصر x، فستخصِّص جو لها ذاكرةً تتسع لعدد العناصر المُحدَّد x، وبالتالي لا يمكنك لاحقًا الإضافة إلى هذه المصفوفة أكثر من x عنصر، فصحيح أنّ ذلك يُفقدها المرونة، إلا أنه يجعلها أسرع.
</p>

<p>
	وتتسم الشرائح في جو بكونها ديناميكيةً، مما يُتيح لك تغيير حجمها باستمرار أينما دعت الحاجة لذلك، وتعطي الخاصية الديناميكية المرونة العالية إلا أن ذلك يكون على حساب الأداء أو السرعة، وتُشبه الشرائح إلى حد كبير مفهوم القوائم Lists في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">لغة البرمجة بايثون</a> والمصفوفات في أغلب <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">اللغات الأخرى</a>، ويمكنك في العديد من المواقف استخدام المصفوفات أو الشرائح، لكن في الحالات التي تحتاج فيها إلى زيادة أو تقليل عدد العناصر، فلا بد من استخدام الشرائح، لأنه في حالة المصفوفات لن تكون قادرًا على ذلك.
</p>

<p>
	سيغطّي هذا المقال المصفوفات والشرائح بالتفصيل، كما سيزودك بالمعلومات الضرورية لاتخاذ القرار المناسب عند الاختيار بين أنواع البيانات هذه، وستراجع أيضًا الطرق الشائعة للتصريح والعمل مع كل من المصفوفات والشرائح.
</p>

<h2>
	المصفوفات
</h2>

<p>
	تُعَدّ المصفوفة <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-data-structures/" rel="">بنية معطيات</a> تجميعية تتألف من مجموعة من العناصر من النوع نفسه، وكل عنصر في المصفوفة يمكنه تخزين قيمة واحدة فيه.
</p>

<p>
	تتميز عناصر المصفوفة عن بعضها من خلال عدد محدد يعطى لكل عنصر ويسمى فهرسًا index، بحيث يكون فهرس أول عنصر في المصفوفة 0 دائمًا، كما تُحدَّد سعة المصفوفة لحظة إنشائها، وبمجرد تعريف حجمها لا يمكن تغييره، وبما أنّ حجم المصفوفة ثابت، فهذا يعني أنه يخصص الذاكرة مرةً واحدةً فقط، مما يجعل المصفوفات غير مرنة نوعًا ما للعمل معها، لكنه يزيد من أداء برنامجك، لهذا السبب تُستخدَم المصفوفات عادةً عند تحسين البرامج.
</p>

<h3>
	تعريف المصفوفات
</h3>

<p>
	تُعرّف المصفوفات من خلال التصريح عن حجمها ضمن قوسين <code>[ ]</code> ثم نوع البيانات ثم القيم المحددة بين الأقواس المعقوصة <code>{ }</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_12" style=""><span class="pun">[</span><span class="pln">capacity</span><span class="pun">]</span><span class="pln">data_type</span><span class="pun">{</span><span class="pln">element_values</span><span class="pun">}</span></pre>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_14" style=""><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"blue coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"staghorn coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: تمثِّل كل مصفوفة تُعرّفها نوع بيانات مختلف بحد ذاته اعتمادًا على نوع البيانات data_type والحجم capacity، فالمصفوفة السابقة مثلًا من نوع <code>string</code> وحجمها 3، تختلف عن مصفوفة من نوع <code>string</code> وحجمها 2.
</p>

<p>
	عندما تُصرّح عن مصفوفة بدون تهيئتها بقيم أوليّة، فستُعدّ لغة جو أنّ قيم جميع العناصر أصفار في حالة الأعداد وفي حالة السلاسل <code>''"</code>، فالمصفوفة التالية مثلًا لم نحدد لها قيمًا أوليّةً، وبالتالي ستهيئها جو بأصفار على أساس قيم افتراضية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_16" style=""><span class="pln">var numbers </span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="typ">int</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_25">[0 0 0]</pre>

<p>
	يمكنك أيضًا إسناد قيم عناصر المصفوفة عند إنشائها بوضعها ضمن قوسين معقوصين <code>{ }</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_20" style=""><span class="pln">coral </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"blue coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"staghorn coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">)</span></pre>

<p>
	خزنا المصفوفة ضمن متغير ثم طبعنا قيمتها ويكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_27">[blue coral staghorn coral pillar coral elkhorn coral]</pre>

<p>
	لاحظ أنه لا يوجد فصل واضح بين العناصر المطبوعة، لذا يُفضَّل استخدام الدالة <code>()fmt.Printf</code> مع العنصر النائب <code>q%</code> لكي توضَع علامتَي اقتباس مزدوجة لكل عنصر لتحديده:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_24" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> coral</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_29">["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]</pre>

<p>
	وضعنا الرمز <code>n\</code> للنزول سطر بعد طباعة المصفوفة.
</p>

<h3>
	فهرسة المصفوفات والشرائح
</h3>

<p>
	يمكن استدعاء عنصر محدد من المصفوفة أو الشريحة من خلال الفهرسة، إذ يمتلك كل عنصر فهرسًا والذي قيمته <code>int</code> تبدأ من الصفر وتزداد تصاعديًا.
</p>

<p>
	سنستخدِم مصفوفةً في الأمثلة التالية، ولكن يمكنك أيضًا استخدام شريحة، إذ ستكون الفهرسة متطابقةً في كل منهما، فمن أجل المصفوفة <code>coral</code> ستكون الفهرسة كما يلي:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				"blue coral"
			</th>
			<th>
				"staghorn coral"
			</th>
			<th>
				"pillar cora"
			</th>
			<th>
				"elkhorn coral"
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				3
			</td>
			<td>
				2
			</td>
			<td>
				1
			</td>
			<td>
				0
			</td>
		</tr>
	</tbody>
</table>

<p>
	لاحظ أنّ العنصر الأول blue coral يحمل الفهرس رقم 0 ويحمل العنصر الأخير elkhorn coral الفهرس رقم 3.
</p>

<p>
	بما أن كل عنصر يمتلك فهرسًا خاصًا به، يمكننا الوصول إلى العنصر الذي نريده من خلال هذا الفهرس وإجراء العمليات عليه، فمثلًا نريد الآن الوصول إلى العنصر الثاني من المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_28" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">])</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_31">staghorn coral</pre>

<p>
	كما يمكنك بالطريقة ذاتها الوصول إلى أيّ عنصر من المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_32" style=""><span class="pln">coral</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"blue coral"</span><span class="pln">
coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"staghorn coral"</span><span class="pln">
coral</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln">
coral</span><span class="pun">[</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"elkhorn coral"</span></pre>

<p>
	لاحظ أن هناك 4 عناصر في المصفوفة، وبالتالي تكون الفهارس من 0 إلى 3، لذا لا تحاول وضع فهرس خارج هذه الحدود، فإذا حاولت مثلًا في المصفوفة السابقة الوصول إلى عنصر يحمل الفهرس 4 أو 5 أو 18، فسيظهر لك خطأ لأن هذا العنصر غير موجود أو أنك تتجاوز حدود المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_34" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[</span><span class="lit">18</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_33">panic: runtime error: index out of range</pre>

<p>
	في العديد من لغات البرمجة الأخرى مثل بايثون، يمكنك الوصول للعناصر من خلال الفهرسة السلبية، لكن لا يمكنك ذلك في جو، أي يجب استخدام الأعداد الموجبة للوصول إلى العناصر، وإلا سيظهر لك خطأ كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_38" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_35">invalid array index -1 (index must be non-negative)</pre>

<p>
	يمكنك ضم عناصر سلسلة في مصفوفة أو شريحة مع سلاسل أخرى باستخدام العامل <code>+</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_43" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy loves "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> coral</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_37">Sammy loves blue coral</pre>

<p>
	تمكنا من وصل العنصر الموجود في الفهرس رقم 0 بالسلسلة النصية Sammy loves، لأن كل عنصر في المصفوفة هو سلسلة نصية بحد ذاته بما أننا حددنا نوع بيانات المصفوفة على أنه <code>string</code> وبالتالي كل عنصر فيها يُمثّل سلسلةً نصيةً.
</p>

<p>
	يمكننا الوصول إلى كل عنصر بصورة منفصلة والعمل مع تلك العناصر باستخدام أعداد الفهرس التي تتوافق مع العناصر داخل مصفوفة أو شريحة ما.
</p>

<h3>
	تعديل عناصر المصفوفة
</h3>

<p>
	يمكنك تعديل قيمة عنصر محدَّد ضمن المصفوفة بالطريقة نفسها التي تُعدّل فيها قيمة متغير من أيّ نوع بيانات وذلك بعد الوصول إلى ذلك العنصر من خلال رقم الفهرس الخاص به، ويمنحنا هذا مزيدًا من التحكم في البيانات الموجودة في الشرائح والمصفوفات، كما سيسمح لنا بمعالجة العناصر الفردية برمجيًا.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_47" style=""><span class="pln">coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"foliose coral"</span></pre>

<p>
	سنطبع الآن المصفوفة لنرى التعديل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_49" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> coral</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_7">["blue coral" "foliose coral" "pillar coral" "elkhorn coral"]</pre>

<h3>
	معرفة حجم المصفوفة
</h3>

<p>
	الآن بعد أن عرفت كيفية التعامل مع العناصر الفردية لمصفوفة أو شريحة، دعنا نلقي نظرةً على دالتين ستمنحانك مزيدًا من المرونة عند العمل مع بُنى المعطيات هذه. الدالة الأولى هي <code>()len</code> وهي دالة مُضمّنة في جو تساعدك على العمل مع المصفوفات والشرائح، بحيث نُمرر لهذه الدالة المصفوفة أو الشريحة وتعيد لنا عدد عناصرها كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_53" style=""><span class="pln">len</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج 4 لأن عدد العناصر في المصفوفة هو 4.
</p>

<p>
	مثال آخر، سننشئ مصفوفة أعداد صحيحة ونحسب عدد عناصرها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_57" style=""><span class="pln">numbers </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">13</span><span class="pun">]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">))</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_10">13</pre>

<p>
	قد لا نشعر بأهمية استخدام هذه الدالة عندما يكون عدد عناصر المصفوفة قليلًا كما في الأمثلة السابقة، لكن عندما نتعامل مع مصفوفات كبيرة، ستظهر الحاجة أكثر لهذه الدالة، كما سنغطي بعد ذلك كيفية إضافة عنصر إلى نوع بيانات المجموعة ونوضِّح كيف أنّ إلحاق أنواع البيانات الثابتة هذه -بسبب الطول الثابت للمصفوفات- سيؤدي إلى حدوث خطأ.
</p>

<h3>
	إضافة عناصر إلى مصفوفة
</h3>

<p>
	الدالة الأخرى التي سنتعرّف عليها هي <code>()append</code> وهي خاصة بالشرائح، إذ تضيف هذه الدالة عنصرًا جديدًا إلى الشريحة، ولا يمكن استخدام هذه الدالة مع المصفوفات لأن المصفوفات لا يمكن تغيير حجمها ببساطة كما سبق وذكرنا، فلتكن لدينا المصفوفة التالية على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_62" style=""><span class="pln">coral </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"blue coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pun">}</span></pre>

<p>
	إذا حاولت إضافة عنصر جديد black coral إلى هذه المصفوفة من خلال الدالة <code>()append</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_64" style=""><span class="pln">coral </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">,</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pun">)</span></pre>

<p>
	ستحصل على خطأ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_66" style=""><span class="pln">first argument to append must be slice</span><span class="pun">;</span><span class="pln"> have </span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">string</span></pre>

<p>
	ولحل هذه المشكلة، سنلجأ إلى نوع بيانات آخر وهو الشرائح.
</p>

<h2>
	الشرائح
</h2>

<p>
	تُعَدّ الشريحة تسلسلًا مرتبًا من العناصر والتي يمكن أن يتغير طولها (قابلة للتغيير)، حيث يمكن للشرائح أن تزيد حجمها ديناميكيًا، فعند إضافة عناصر جديدة إلى شريحة وإذا لم يكن للشريحة حجم ذاكرة كافي لتخزين العناصر الجديدة، فستطلب ذاكرةً أكبر من النظام حسب الحاجة، ولهذا السبب هي شائعة الاستخدام أكثر من المصفوفات.
</p>

<p>
	تمكّنك الخاصيّة الديناميكية للشرائح من العمل معها في الحالات التي تحتاج فيها إلى تغيير طول عدد عناصر البيانات بأمان، وهذه هي الخاصية الوحيدة التي تتميز بها الشرائح عن المصفوفات.
</p>

<h3>
	التصريح عن شريحة
</h3>

<p>
	يُصرّح عن الشرائح من خلال تحديد نوع البيانات مسبوقًا بقوسَي فتح وإغلاق مربعَين <code>[]</code> ليس فيهما أي قيمة -خلاف نوع المصفوفة التي تحتاج إلى تحديد حجمها- وقيم بين أقواس معقوصة <code>{}</code>. وتكون شريحة من الأعداد الصحيحة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_68" style=""><span class="pun">[]</span><span class="typ">int</span><span class="pun">{-</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">}</span></pre>

<p>
	شريحة من الأعداد الحقيقية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_70" style=""><span class="pun">[]</span><span class="typ">float64</span><span class="pun">{</span><span class="lit">3.14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9.23</span><span class="pun">,</span><span class="pln"> </span><span class="lit">111.11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">312.12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1.05</span><span class="pun">}</span></pre>

<p>
	شريحة من السلاسل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_72" style=""><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cuttlefish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"mantis shrimp"</span><span class="pun">}</span></pre>

<p>
	يمكنك أيضًا إسنادها إلى متغير:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_74" style=""><span class="pln">seaCreatures </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cuttlefish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"mantis shrimp"</span><span class="pun">}</span></pre>

<p>
	ثم طباعة هذا المتغير:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_76" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">seaCreatures</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_12">[shark cuttlefish squid mantis shrimp]</pre>

<p>
	مثال آخر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_80" style=""><span class="pln">seaCreatures </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cuttlefish"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"mantis shrimp"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"anemone"</span><span class="pun">}</span></pre>

<p>
	سنطبع الشريحة لكن باستخدام الدالة <code>()fmt.Printf</code> مع العنصر النائب <code>q%</code> كما فعلنا مع المصفوفات سابقًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_82" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> seaCreatures</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_14">["shark" "cuttlefish" "squid" "mantis shrimp" "anemone"]</pre>

<p>
	إذا رغبت في إنشاء شريحة بطول معيّن دون تحديد عناصرها، فيمكنك استخدام الدالة <code>()make</code> المضمنة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_86" style=""><span class="pln">oceans </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span></pre>

<p>
	فإذا طبعناها، فسيكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_16">["" "" ""]</pre>

<p>
	يمكنك أيضًا إنشاء شريحة بطول محدَّد كما فعلنا أعلاه لكن مع حجز مساحة إضافية من خلال تمرير عدد العناصر التي نريد حجز ذاكرة لها بصورة استباقية على أساس وسيط ثالث:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_91" style=""><span class="pln">oceans </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span></pre>

<p>
	المقصود هنا أنه ستُنشأ شريحة بطول 3 لكن ستُحجز ذاكرة لخمس عناصر إضافية، أي ستحجز بالمجمل 8 عناصر، والهدف من ذلك هو تحسين الأداء، أي نتوقع أنه ستُضاف 5 عناصر على الأكثر لاحقًا، فنحجز لهم ذاكرةً مسبقًا لتجنب التأخير الذي سيحدث عند حجز ذاكرة إضافية في وقت تشغيل البرنامج بحيث نستفيد من الخاصية الديناميكية والأداء كما في المصفوفات.
</p>

<p>
	يمكنك استخدام الدالة <code>()append</code> التي تحدثنا عنها سابقًا لإضافة عنصر جديد إلى الشريحة.
</p>

<h3>
	تقطيع المصفوفات
</h3>

<p>
	تدعم المصفوفات إضافةً إلى الفهرسة عملية الاقتطاع slicing أيضًا، إذ تُستخدم الفهرسة للحصول على عناصر مفردة؛ أما عملية الاقتطاع فتتيح الحصول على جزء من المصفوفة، أي عدة عناصر متتالية، ويمكنك إجراء ذلك عن طريق إنشاء نطاق من أرقام الفهرس مفصولةً بنقطتين على صورة [الفهرس الأول: الفهرس الثاني] أو [first_index:second_index]، ومن المهم ملاحظة أنه عند تقطيع المصفوفة ستكون النتيجة شريحةً وليست مصفوفةً.
</p>

<p>
	لنفترض أنك ترغب فقط في طباعة العناصر الوسطى من المصفوفة <code>coral</code> بدون العنصر الأول والأخير، إذ يمكنك إجراء ذلك عن طريق إنشاء شريحة تبدأ من الفهرس 1 وتنتهي قبل الفهرس 3 مباشرةً كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_93" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:</span><span class="lit">3</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_18">[foliose coral pillar coral]</pre>

<p>
	لاحظ أننا وضعنا الرقم 1 ثم نقطتين ثم 3، بالنسبة للرقم 1 فقد وضعناه لأنه يمثّل نقطة البداية حيث يتواجد ثاني عنصر من المصفوفة؛ أما 3 فهو نقطة النهاية لكنها لا تؤخذ، وإنما تؤخذ القيمة التي قبلها مباشرةً، أي أنه ستؤخذ العناصر من 1 إلى 2، باختصار، العنصر المُحدد بالرقم الأول سيكون مشمولًا دائمًا بعملية الاقتطاع؛ أما العنصر المُحدد بالرقم الأخير فلن يكون مشمولًا.
</p>

<p>
	هناك بعض القيم الافتراضية المفيدة في خاصية التقطيع، فإذا حُذف الفهرس رقم 1 first_index -أي العنصر الثاني-، فستكون القيمة الافتراضية له صفرًا، وإذا حُذف الرقم الثاني second_index فإنّ القيمة الافتراضية تكون طول السلسلة النصية التي سيجري اقتطاعها.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_97" style=""><span class="pln">coral</span><span class="pun">[:</span><span class="lit">2</span><span class="pun">]</span><span class="pln">   </span><span class="com">// اقتطاع العناصر من الموقع 0 إلى الموقع 2 (غير مشمول)‏</span><span class="pln">
coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:]</span><span class="pln">   </span><span class="com">// اقتطاع العناصر من الموقع 1 (مشمول) إلى نهاية السلسلة</span></pre>

<p>
	نريد مثلًا من أول عنصر حتى العنصر الثاني:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_99" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[:</span><span class="lit">3</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_20">[blue coral foliose coral pillar coral]</pre>

<p>
	أو مثلًا نريد من العنصر الأول حتى النهاية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_103" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">coral</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3182_22">[foliose coral pillar coral elkhorn coral]</pre>

<h3>
	التحويل من مصفوفة إلى شريحة
</h3>

<p>
	في حال احتجت إلى تغيير حجم المصفوفة يمكنك تحويلها إلى شريحة من خلال الآلية التي اتبعناها في الفقرة السابقة لتقطيع المصفوفة، ويمكن إنجاز ذلك من خلال استخدام النقطتين <code>:</code> بدون تحديد البداية أو النهاية، أي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_107" style=""><span class="pln">coral</span><span class="pun">[:]</span></pre>

<p>
	لاحظ أنه هنا لا يُحوّل المُتغير بحد ذاته -والذي يمثّل المصفوفة- إلى شريحة، لكن ما يحدث هو أنه عند استخدامك للتقطيع مع المصفوفات، ستُعيد جو نسخةً تمثّل الجزء الذي اقتطعته على أساس شريحة، أي أنّ المتغير <code>coral</code> نفسه لا يحوّل، وإنما تُعاد نسخة منه، وهذا منطقي، ففي جو لا يمكنك تغيير نوع المتغير مهما كان نوعه، إذًا نكتب كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_109" style=""><span class="pln">coralSlice </span><span class="pun">:=</span><span class="pln"> coral</span><span class="pun">[:]</span></pre>

<p>
	إذًأ ستمثّل <code>coralSlice</code> نسخة شريحة من المصفوفة <code>coral</code>، فإذا طبعناها، فسنحصل على ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_112" style=""><span class="pun">[</span><span class="pln">blue coral foliose coral pillar coral elkhorn coral</span><span class="pun">]</span></pre>

<p>
	يمكنك الآن مثلًا إضافة عنصر جديد وليكن <code>black coral</code> إلى الشريحة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_114" style=""><span class="pln">coralSlice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coralSlice</span><span class="pun">,</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> coralSlice</span><span class="pun">)</span></pre>

<p>
	سنحصل على الخرج التالي عند طباعتها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_116" style=""><span class="pun">[</span><span class="str">"blue coral"</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pun">]</span></pre>

<p>
	يمكنك أيضًا إضافة أكثر من عنصر دفعةً واحدةً:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_118" style=""><span class="pln">coralSlice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coralSlice</span><span class="pun">,</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_122" style=""><span class="pun">[</span><span class="str">"blue coral"</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pun">]</span></pre>

<p>
	يمكنك دمج شريحتين معًا من خلال <code>()append</code> لكن يجب أن تضع ثلاث نقاط <code>...</code> بعد اسم الشريحة الثانية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_120" style=""><span class="pln">moreCoral </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"massive coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">}</span><span class="pln">
coralSlice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coralSlice</span><span class="pun">,</span><span class="pln"> moreCoral</span><span class="pun">...)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_124" style=""><span class="pun">[</span><span class="str">"blue coral"</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pln"> </span><span class="str">"massive coral"</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">]</span></pre>

<h3>
	حذف عنصر من شريحة
</h3>

<p>
	لا تمتلك جو دوالًا جاهزةً مثل باقي اللغات لحذف عنصر، إذ يجب عليك الاعتماد على مبدأ التقطيع لحذف العناصر، فلحذف عنصر يجب عليك تقطيع الشريحة لشريحتين، بحيث تمثِّل الأولى جميع العناصر التي قبله وتمثِّل الثانية العناصر الذي بعده، ثم دمج هاتين الشريحتين الجديدتين معًا بدون العنصر الذي تريد حذفه، أي كما يلي بفرض أنّ <code>i</code> هو فهرس العنصر المراد إزالته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_126" style=""><span class="pln">slice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">slice</span><span class="pun">[:</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> slice</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">:]...)</span></pre>

<p>
	نريد فرضًا حذف العنصر <code>elkhorn coral</code> الموجود في الفهرس 3 من الشريحة <code>coralSlice</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_128" style=""><span class="pln">coralSlice </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"blue coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"massive coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">}</span><span class="pln">

coralSlice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coralSlice</span><span class="pun">[:</span><span class="lit">3</span><span class="pun">],</span><span class="pln"> coralSlice</span><span class="pun">[</span><span class="lit">4</span><span class="pun">:]...)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> coralSlice</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_130" style=""><span class="pun">[</span><span class="str">"blue coral"</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pln"> </span><span class="str">"massive coral"</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">]</span></pre>

<p>
	نلاحظ أنّ العنصر الذي حددناه قد حُذف من الشريحة، ويمكنك أيضًا حذف عدة قيم أو مجال من القيم دفعةً واحدةً، إذ تريد مثلًا حذف <code>"elkhorn coral"</code> و <code>"black coral"</code> و <code>"antipathes"</code>، أي تريد حذف العناصر الموجودة في الفهارس 3 و 4 و 5:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_132" style=""><span class="pln">coralSlice </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"blue coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"elkhorn coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"black coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"antipathes"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"massive coral"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">}</span><span class="pln">

coralSlice </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">coralSlice</span><span class="pun">[:</span><span class="lit">3</span><span class="pun">],</span><span class="pln"> coralSlice</span><span class="pun">[</span><span class="lit">6</span><span class="pun">:]...)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> coralSlice</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_134" style=""><span class="pun">[</span><span class="str">"blue coral"</span><span class="pln"> </span><span class="str">"foliose coral"</span><span class="pln"> </span><span class="str">"pillar coral"</span><span class="pln"> </span><span class="str">"leptopsammia"</span><span class="pln"> </span><span class="str">"massive coral"</span><span class="pln"> </span><span class="str">"soft coral"</span><span class="pun">]</span></pre>

<h3>
	عدد عناصر الشريحة
</h3>

<p>
	صحيح أنه يمكنك استخدام التابع <code>()len</code> لمعرفة عدد عناصر الشريحة، لكنه سيعطيك عدد العناصر الظاهرة وليس عدد العناصر التي حُجز لها مكان في الذاكرة، وللتوضيح، يجب عليك العودة إلى الدالة <code>()make</code> وتتذكر حينما كتبنا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_136" style=""><span class="pln">oceans </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span></pre>

<p>
	هنا أنشأنا شريحة عدد عناصرها الظاهر 3 لكن حجزنا ذاكرة لخمسة عناصر وقد شرحنا ذلك سابقًا، فإذا استخدمنا الآن الدالة <code>()len</code> لمعرفة عدد عناصر الشريحة <code>oceans</code>، فستُعيد 3؛ أما إذا استخدمنا الدالة <code>()cap</code>، فستعطي 5 وهذا هو الفرق الوحيد بينهما.
</p>

<p>
	لاحظ أن الدالة <code>()cap</code> ليس لاستخدامها معنًى مع المصفوفات لأن الحجم ثابت، أي الحجم الظاهر هو نفسه المحجوز دومًا، لذا اقتصر تعريف <code>()cap</code> على العمل مع الشرائح ولا تعمل مع المصفوفات.
</p>

<p>
	الاستخدام الشائع للدالة <code>()cap</code> هو إنشاء شريحة بعدد محدد مسبقًا من العناصر ثم ملء تلك العناصر برمجيًا، إذ يؤدي ذلك إلى تجنب عمليات التخصيص غير الضرورية المحتملة التي قد تحدث باستخدام <code>()append</code> لإضافة عناصر تتجاوز السعة المخصصة حاليًا كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_138" style=""><span class="pln">numbers </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    numbers </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_140" style=""><span class="pun">[</span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span></pre>

<p>
	أنشأنا شريحةً ثم أنشأنا حلقة <code>for</code> تتكرر أربع مرات. أضفنا في كل تكرار القيمة الحالية لمتغير الحلقة <code>i</code> إلى شريحة الأعداد <code>numbers</code>، وقد يؤدي ذلك إلى عمليات تخصيص غير ضرورية للذاكرة والتي قد تؤدي إلى إبطاء برنامجك، فعند إضافة عناصر إلى شريحة فارغة، فإنه في كل مرة تستدعي فيها الدالة <code>()append</code> تتحقق جو من سعة الشريحة، فإذا كان العنصر المضاف سيجعل الشريحة تتجاوز هذه السعة، فستُخصص ذاكرة إضافية لها، مما يؤدي إلى إنشاء عبء إضافي في برنامجك ويمكن أن يؤدي إلى إبطاء التنفيذ.
</p>

<p>
	سنملأ الآن الشريحة بدون استخدام <code>()append</code> وذلك عن طريق التخصيص المسبق للعناصر كما تعلمت سابقًا في بداية المقال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_142" style=""><span class="pln">numbers </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="typ">int</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cap</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">);</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    numbers</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i
</span><span class="pun">}</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_144" style=""><span class="pun">[</span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span></pre>

<p>
	استخدمنا هنا الدالة <code>()make</code> لإنشاء شريحة وجعلناها تخصص 4 عناصر مسبقًا، ثم استخدمنا بعد ذلك الدالة <code>()cap</code> في الحلقة للتكرار على كل عنصر من الشريحة (العناصر تكون كلها أصفار كما أشرنا سابقًا)، ثم ملأنا الشريحة بالقيم التي نريدها وهي قيم متغير الحلقة <code>i</code>، ولاحظ أنّ استخدام الدالة <code>()cap</code> هنا بدلًا من <code>()append</code> سيتجنب أيّ تخصيصات إضافية للذاكرة.
</p>

<h3>
	الشرائح متعددة الأبعاد
</h3>

<p>
	يمكنك أيضًا تعريف الشرائح متعددة الأبعاد، أي شريحة تتضمّن شريحةً أو أكثر؛ يمكن القول شرائح متداخلة، إذ نضع هنا الشرائح ضمن قوسين داخل الشريحة التي تضمها. مثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_146" style=""><span class="pln">seaNames </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[][]</span><span class="pln">string</span><span class="pun">{{</span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"octopus"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"squid"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"mantis shrimp"</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jesse"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">}}</span></pre>

<p>
	يجب عليك استخدام عدة مؤشرات للوصول إلى عنصر داخل هذه الشريحة، بحيث نستخدِم مؤشرًا واحدًا لكل بُعد من أبعاد البنية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_148" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">seaNames</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="lit">0</span><span class="pun">])</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">seaNames</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">0</span><span class="pun">])</span></pre>

<p>
	تعني التعليمة <code>[seaNames[1][0</code> أنك تريد الوصول إلى العنصر الأول 0 من الشريحة ذات الفهرس 1؛ أما التعليمة الثانية، فتشير إلى أنك تريد الوصول إلى العنصر الأول 0 من الشريحة ذات الفهرس 0، لذا سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_150" style=""><span class="typ">Sammy</span><span class="pln">
shark</span></pre>

<p>
	فيما يلي قيم الفهرس لبقية العناصر الفردية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8803_152" style=""><span class="pln">seaNames</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"octopus"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"squid"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"mantis shrimp"</span><span class="pln">

seaNames</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Jesse"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Drew"</span><span class="pln">
seaNames</span><span class="pun">[</span><span class="lit">1</span><span class="pun">][</span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Jamie"</span></pre>

<p>
	عند العمل مع الشرائح متعددة الأبعاد من المهم أن تضع في الحسبان أنك ستحتاج إلى الإشارة إلى أكثر من رقم فهرس واحد من أجل الوصول إلى عناصر محددة داخل الشريحة المتداخلة التي تعمل عليها.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعلمت في هذا المقال كيفية العمل مع المصفوفات والشرائح والروابط في جو، وتعرّفت على العديد من حالات الاستخدام لكل منها، كما تعرّفت على بعض الأخطاء الشائعة في التعامل مع هذه البُنى وعلى دوال أساسية فيها، وأصبحت لديك القدرة أيضًا على التفريق بين الشرائح والمصفوفات ومتى تستخدم أيًا منهما.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-arrays-and-slices-in-go" rel="external nofollow">Understanding Arrays and Slices in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/" rel="">التعرف على الروابط Maps في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-go-r840/" rel="">مقدمة عن المصفوفات Arrays والشرائح Slices الخاصة بلغة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-gopath-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1789/" rel="">التعرف على GOPATH في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1866</guid><pubDate>Tue, 17 Jan 2023 05:56:16 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x627;&#x644;&#x62E;&#x631;&#x627;&#x626;&#x637; Maps &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-maps-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1865/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1731938262_Sans-titre---5-15--Maps---Go.png.2e0468c1013735da33227ff040b05c11.png" /></p>
<p>
	تمتلك معظم <span ipsnoautolink="true">لغات البرمجة</span> نوع بيانات يُمثّل بنية معطيات يُعرف بالقاموس dictionary أو التجزئة hash، إذ تربط هذه البنية أو هذا النوع البيانات على صورة أزواج (مفتاح-قيمة).
</p>

<p>
	تُعَدّ الخرائط أو الروابط maps مفيدةً للغاية في كثير من الحالات مثل أن تريد إعطاء كل طالب رقمًا يُميّزه عن باقي الطلاب، إذ يمكنك في هذه الحالة تعريف رابطة يربط اسم كل طالب (قيمة) برقم يُميّزه (مفتاح)، فالخرائط Maps في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> هي بنية معطيات توجد في <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات أخرى</a> مثل بايثون، وتُعرّف الخرائط في لغة جو من خلال وضع الكلمة <code>map</code> متبوعةً بنوع بيانات المفاتيح (في مثالنا السابق سيكون أعداد صحيحة) ضمن قوسين <code>[ ]</code> ثم نوع بيانات القيم (سلاسل نصية في مثالنا)، وأخيرًا توضع أزواج (مفتاح، قيمة) ضمن قوسين معقوصين <code>{}</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_9" style=""><span class="typ">map</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln">value</span><span class="pun">{}</span></pre>

<p>
	سيوضّح المثال التالي الأمر أكثر؛ إذ سنعرّف رابطة مفاتيحه هي الاسم <code>name</code> والحيوان <code>animal</code> واللون <code>color</code> والموقع <code>location</code>، وقيمه هي <code>Sammy</code> و <code>shark</code> و <code>blue</code> و <code>ocean</code> على التوالي.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_16" style=""><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"location"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ocean"</span><span class="pun">}</span></pre>

<p>
	لاحظ أنّ المفتاح يُوضَع على اليسار والقيمة على اليمين ويُفصل بينهما بنقطتين <code>:</code> كما يُفصل بين كل زوج (مفتاح:قيمة) بفاصلة <code>,</code> ولاحظ أيضًا أننا استخدمنا نوع البيانات <code>string</code> لكل من القيم والمفاتيح، وهذا ليس إجباريًا، لكنه يعتمد على ما ستستخدِمه من بيانات.
</p>

<p>
	يمكنك تخزين الخرائط ضمن متغيرات كما في أيّ نوع بيانات آخر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_18" style=""><span class="pln">sammy </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"location"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ocean"</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1491_7">map[animal:shark color:blue location:ocean name:Sammy]</pre>

<p>
	لاحظ أنه قد حدث تغيير في مواقع الأزواج عند طباعة الرابطة، وسبب ذلك هو أنّ جو تُخزّن هذه الأزواج ضمن مناطق متفرقة من الذاكرة، فالترتيب هنا غير مهم، وما يهمنا فقط هو أن تكون كل قيمة مرتبطةً بمفتاح نصل إليها من خلاله.
</p>

<h2>
	الوصول إلى عناصر الرابطة
</h2>

<p>
	يمكننا الوصول إلى قيم محدَّدة في الرابطة بالرجوع إلى المفاتيح المرتبطة بها، فإذا أردنا مثلًا الحصول على اسم المستخدِم من الرابطة <code>sammy</code>، فيمكننا ذلك عن طريق كتابة <code>["sammy["name</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_23" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">[</span><span class="str">"name"</span><span class="pun">])</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1491_21">Sammy</pre>

<p>
	تتصرف الخرائط مثل قواعد البيانات، لكن بدلًا من فهرسة العناصر بأعداد صحيحة كما هو الحال في الشرائح slice، فإنها تسند لمفتاح، ويمكنك عبر تلك المفاتيح الحصول على القيم المقابلة لها، أي باستدعاء المفتاح <code>"name"</code>، سنحصل على القيمة المرتبطة به وهي <code>"Sammy"</code>، وبالمِثل، فيمكن استدعاء القيم الأخرى في الرابطة <code>sammy</code> باستخدام الصيغة ذاتها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_29" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">[</span><span class="str">"animal"</span><span class="pun">])</span><span class="pln">
</span><span class="com">//shark تُعيد</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">[</span><span class="str">"color"</span><span class="pun">])</span><span class="pln">
</span><span class="com">//blue تُعيد</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">[</span><span class="str">"location"</span><span class="pun">])</span><span class="pln">
</span><span class="com">//ocean تُعيد</span></pre>

<p>
	من خلال تخزين البيانات على هيئة أزواج (مفتاح:قيمة)، سيصبح بإمكانك الوصول إلى القيمة التي تريدها من خلال ذكر اسم المفتاح الذي يُميّزه.
</p>

<h2>
	المفاتيح والقيم keys/values
</h2>

<p>
	لا تمتلك لغة جو أيّة دوال مُضمّنة تمكّنك من سرد جميع المفاتيح أو القيم، ففي <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> مثلًا هناك الدالة <code>()‎.kyes</code> التي تعرض لك جميع المفاتيح التي تتضمنها الرابطة أو <code>()‎.values</code> التي تعرض كل القيم، لكن يمكنك التكرار على عناصر الرابطة في جو من خلال العامِل <code>range</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_32" style=""><span class="kwd">for</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">:=</span><span class="pln"> range sammy </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q is the key for the value %q\n"</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُعيد <code>range</code> هنا قيمتين من أجل كل زوج في الرابطة، إذ ستُمثِّل القيمة الأولى المفتاح <code>key</code> والثانية القيمة <code>value</code>، كما أنّ نوع بيانات <code>key</code> سيكون نفسه نوع بيانات <code>key</code> في الرابطة <code>sammy</code> والأمر نفسه بالنسبة لمتغير القيمة <code>value</code>، وبالتالي سيكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1491_11">"animal" is the key for the value "shark"
"color" is the key for the value "blue"
"location" is the key for the value "ocean"
"name" is the key for the value "Sammy"</pre>

<p>
	صحيح أنه لا توجد دوال جاهزة لاستخراج المفاتيح، لكن يمكنك استخراجها من خلال كتابة شيفرة بسيطة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_36" style=""><span class="pln">keys </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{}</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> key </span><span class="pun">:=</span><span class="pln"> range sammy </span><span class="pun">{</span><span class="pln">
    keys </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">keys</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q"</span><span class="pun">,</span><span class="pln"> keys</span><span class="pun">)</span></pre>

<p>
	وبالتالي سنحصل على شريحة بجميع المفاتيح:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_39" style=""><span class="pun">[</span><span class="str">"color"</span><span class="pln"> </span><span class="str">"location"</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">]</span></pre>

<p>
	كما ذكرنا هو أنّ المفاتيح غير مرتبة، ولكن يمكنك ترتيبها إذا أردت من خلال الدالة <code>()sort.Strings</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_41" style=""><span class="pln">sort</span><span class="pun">.</span><span class="typ">Strings</span><span class="pun">(</span><span class="pln">keys</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1491_14">["animal" "color" "location" "name"]</pre>

<p>
	يمكنك إجراء الأمر نفسه لاستخراج القيم، لكن هنا سنعرّف شريحةً يكون عدد عناصرها هو عدد الأزواج الموجودة في الرابطة وذلك لكي لا نضطر في كل مرة إلى طلب حجز مساحة إضافية كما فعلنا في المثال السابق حين عرّفنا شريحةً فارغةً ثم في كل تكرار وسّعنا حجمها بإضافة عنصر جديد.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_46" style=""><span class="pln">sammy </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"location"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ocean"</span><span class="pun">}</span><span class="pln">

items </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">))</span><span class="pln">

var i </span><span class="typ">int</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range sammy </span><span class="pun">{</span><span class="pln">
    items</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> v
    i</span><span class="pun">++</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q"</span><span class="pun">,</span><span class="pln"> items</span><span class="pun">)</span></pre>

<p>
	إذًا عرّفنا شريحةً بالحجم المطلوب تمامًا بحيث يقابل عدد عناصر الرابطة (كل عنصر يمثّل زوج)، ثم نُعرّف متغير الفهرسة <code>i</code> وندخل في حلقة التكرار على عناصر الرابطة، ولاحظ أنه وضعنا عامِل <code>_</code> في بداية الحلقة إشارةً إلى أن المفتاح لا نريده، ويكون الخرج كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1491_16">["ocean" "Sammy" "shark" "blue"]</pre>

<p>
	يمكنك استخدام الدالة المضمّنة <code>len</code> لمعرفة عدد العناصر الموجودة في الرابطة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_50" style=""><span class="pln">sammy </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"animal"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"blue"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"location"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ocean"</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">sammy</span><span class="pun">))</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_52" style=""><span class="lit">4</span></pre>

<h2>
	تفقد وجود عنصر في رابطة
</h2>

<p>
	عند محاولة الوصول إلى عنصر غير موجود في القائمة، ستُعيد جو <code>0</code> إشارةً إلى أن هذا العنصر غير موجود في الرابطة، ولهذا السبب ستحتاج إلى طريقة بديلة للتمييز بين الصفر المخزن والمفتاح المفقود، لذا انظر إلى المثال التالي، إذ سنعرّف رابطةً فارغةً ثم سنحاول الوصول إلى عنصر غير موجود:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_54" style=""><span class="pln">counts </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="typ">int</span><span class="pun">{}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">counts</span><span class="pun">[</span><span class="str">"sammy"</span><span class="pun">])</span></pre>

<p>
	نظرًا لأن المفتاح <code>sammy</code> غير موجود، فستعيد جو <code>0</code> كما ذكرنا، فهو يعطي قيمة صفرية تلقائيًا لجميع المتغيرات التي ليس لديها قيمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_56" style=""><span class="lit">0</span></pre>

<p>
	هذا غير مرغوب فيه وقد يؤدي إلى حدوث خلل في برنامجك في الكثير من الحالات، ولحل المشكلة هناك قيمة اختيارية ثانية يمكنك الحصول عليها عند البحث عن عنصر في الرابطة، وهي قيمة منطقية <code>bool</code> تُدعى <code>ok</code> وتكون قيمتها <code>true</code> إذا عُثِر على العنصر أو <code>false</code> إذا لم يُعثر على العنصر، وتستخدَم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_58" style=""><span class="pln">count</span><span class="pun">,</span><span class="pln"> ok </span><span class="pun">:=</span><span class="pln"> counts</span><span class="pun">[</span><span class="str">"sammy"</span><span class="pun">]</span></pre>

<p>
	يمكنك إذا أحببت استخدام هذه القيمة المُعادة <code>ok</code> لطباعة رسالة تُرشدك فيما إذا كان العنصر موجودًا أم لا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_60" style=""><span class="kwd">if</span><span class="pln"> ok </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Sammy has a count of %d\n"</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy was not found"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_62" style=""><span class="typ">Sammy</span><span class="pln"> was not found</span></pre>

<p>
	يمكنك في جو الجمع بين التصريح عن متغير والفحص الشرطي مع كتلة <code>if/else</code>، إذ يتيح لك هذا اختصار التعليمات البرمجية لإنجاز عملية الفحص:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_64" style=""><span class="kwd">if</span><span class="pln"> count</span><span class="pun">,</span><span class="pln"> ok </span><span class="pun">:=</span><span class="pln"> counts</span><span class="pun">[</span><span class="str">"sammy"</span><span class="pun">];</span><span class="pln"> ok </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Sammy has a count of %d\n"</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy was not found"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عند محاولة الوصول لعنصر ضمن رابطة ما في جو، من الأفضل التحقق من وجودها لتجنب <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">الزلات أو الأخطاء البرمجية</a> في برنامجك.
</p>

<h1>
	تعديل الخريطة Map
</h1>

<p>
	تُعَدّ الخرائط هياكل بيانات قابلة للتغيير mutable، أي يمكن تعديلها، وسنتعلم في هذا القسم كيفية إضافة عناصر إلى رابطة وكيفية حذفها.
</p>

<h2>
	إضافة وتغيير عناصر الرابطة
</h2>

<p>
	يمكنك إضافة أزواج قيمة-مفتاح إلى رابطة دون استخدام توابع أو دوال باستخدام الصياغة التالية، حيث نضع اسم متغير الرابطة متبوعةً بالمفتاح بين قوسين <code>[]</code> متبوعة بالعامل <code>=</code> ثم القيمة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_67" style=""><span class="typ">map</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> value</span></pre>

<p>
	سنضيف في المثال التالي زوج مفتاح-قيمة إلى رابطة تُسمى <code>usernames</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_70" style=""><span class="pln">usernames </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"sammy-shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mantisshrimp54"</span><span class="pun">}</span><span class="pln">

usernames</span><span class="pun">[</span><span class="str">"Drew"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"squidly"</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">usernames</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_72" style=""><span class="typ">map</span><span class="pun">[</span><span class="typ">Drew</span><span class="pun">:</span><span class="pln">squidly </span><span class="typ">Jamie</span><span class="pun">:</span><span class="pln">mantisshrimp54 </span><span class="typ">Sammy</span><span class="pun">:</span><span class="pln">sammy</span><span class="pun">-</span><span class="pln">shark</span><span class="pun">]</span></pre>

<p>
	لاحظ أنّ الرابطة حُدّثت بالزوج <code>Drew:squidly</code> نظرًا لأنّ الخرائط غير مرتبة، فيمكن أن يظهر الزوج المُضاف في أيّ مكان في مخرجات الرابطة، فإذا استخدمنا الرابطة <code>usernames</code> لاحقًا في ملف برنامجك، فسيظهر فيه الزوج المضاف حديثًا.
</p>

<p>
	يمكن استخدام هذه الصياغة لتعديل القيمة المرتبطة بمفتاح معيّن، ففي هذه الحالة سنشير إلى مفتاح موجود سلفًا ونمرِّر قيمةً مختلفةً إليه.
</p>

<p>
	سنعرِّف في المثال التالي رابطة باسم <code>followers</code> لتعقّب متابِعي المستخدِمين على شبكة معيّنة، إذ حصل المستخدِم <code>"drew"</code> على عدد من المتابعين الإضافيين اليوم، لذلك سنحدّث القيمة المرتبطة بالمفتاح <code>"drew"</code> ثم سنستخدِم الدالة <code>Println()‎</code> للتحقق من تعديل الرابطة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_74" style=""><span class="pln">followers </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="typ">int</span><span class="pun">{</span><span class="str">"drew"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">305</span><span class="pun">,</span><span class="pln"> </span><span class="str">"mary"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">428</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cindy"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">918</span><span class="pun">}</span><span class="pln">
followers</span><span class="pun">[</span><span class="str">"drew"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">342</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">followers</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_76" style=""><span class="typ">map</span><span class="pun">[</span><span class="pln">cindy</span><span class="pun">:</span><span class="lit">918</span><span class="pln"> drew</span><span class="pun">:</span><span class="lit">342</span><span class="pln"> mary</span><span class="pun">:</span><span class="lit">428</span><span class="pun">]</span></pre>

<p>
	نرى في الخرج السابق أنّ عدد المتابعين قد قفز من 305 إلى 342.
</p>

<p>
	a يمكننا استخدام هذه الطريقة لإضافة أزواج قيمة-مفتاح إلى الخرائط عبر مدخلات المستخدِم، إذَا سنكتب برنامجًا سريعًا <code>usernames.go</code> يعمل من <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> ويسمح للمستخدِم بإضافة الأسماء وأسماء المستخدِمين المرتبطة بها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_78" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    usernames </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Sammy"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"sammy-shark"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Jamie"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mantisshrimp54"</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Enter a name:"</span><span class="pun">)</span><span class="pln">

        var name string
        _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Scanln</span><span class="pun">(&amp;</span><span class="pln">name</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            panic</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        name </span><span class="pun">=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">TrimSpace</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> u</span><span class="pun">,</span><span class="pln"> ok </span><span class="pun">:=</span><span class="pln"> usernames</span><span class="pun">[</span><span class="pln">name</span><span class="pun">];</span><span class="pln"> ok </span><span class="pun">{</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q is the username of %q\n"</span><span class="pun">,</span><span class="pln"> u</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">continue</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"I don't have %v's username, what is it?\n"</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">

        var username string
        _</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Scanln</span><span class="pun">(&amp;</span><span class="pln">username</span><span class="pun">)</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
            panic</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        username </span><span class="pun">=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">TrimSpace</span><span class="pun">(</span><span class="pln">username</span><span class="pun">)</span><span class="pln">

        usernames</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> username

        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Data updated."</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نُعرّف أولًا الرابطة ضمن ملف <code>usernames.go</code> ، ثم نضبط حلقة التكرار على الأسماء، وتطلب بعد ذلك من المستخدِم إدخال اسم وتصرّح عن متغير لتخزِّنه فيه، ويجب أن تتحقق بعد ذلك من حدوث خطأ في عملية الإدخال من المستخدِم، ففي حال حدث خطأ، فستخرج من البرنامج.
</p>

<p>
	تلتقط الدالة <code>Scanln</code> المُدخلات التي يدخلها المستخدِم بالكامل بما في ذلك محرف العودة إلى بداية السطر Carriage return، لذا أنت بحاجة إلى إزالة أي فراغ زائد من الدخل باستخدام الدالة <code>strings.TrimSpace</code>.
</p>

<p>
	تتحقق كتلة <code>if</code> من وجود الاسم في الرابطة أو لا، فإذا لم يكن الاسم موجودًا، فسيطبع ملاحظات للمستخدِم تُشير إلى ذلك ثم يطلب إدخال اسم جديد، ويتحقق البرنامج مرةً أخرى من وجود خطأ، ففي حال لم يكن هناك خطأ، فسيَقص محرف الإرجاع ويُسند الاسم المُدخل من المستخدِم على أساس قيمة لمفتاح الاسم ثم يطبع الملاحظات التي تفيد بأن البيانات قد حُدّثت.
</p>

<p>
	سننفِّذ البرنامج من سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_81" style=""><span class="pln">$ go run usernames</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	سترى الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_83" style=""><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln">
</span><span class="typ">Sammy</span><span class="pln">
</span><span class="str">"sammy-shark"</span><span class="pln"> is the username of </span><span class="str">"Sammy"</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span><span class="pln">
</span><span class="typ">Jesse</span><span class="pln">
I don</span><span class="str">'t have Jesse'</span><span class="pln">s username</span><span class="pun">,</span><span class="pln"> what is it</span><span class="pun">?</span><span class="pln">
</span><span class="typ">JOctopus</span><span class="pln">
</span><span class="typ">Data</span><span class="pln"> updated</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Enter</span><span class="pln"> a name</span><span class="pun">:</span></pre>

<p>
	اضغط على <code>CTRL + C</code> عند الانتهاء من اختبار البرنامج للخروج من البرنامج.
</p>

<p>
	يوضح هذا المثال كيف يمكنك تعديل الخرائط بآلية تفاعلية، وستفقد جميع بياناتك بمجرد خروجك من هذا البرنامج باستخدام <code>CTRL + C</code>، إلا إذا خزّنت البيانات في ملف بطريقةٍ ما.
</p>

<p>
	للتلخيص، يمكنك إضافة عناصر إلى الرابطة أو التعديل عليها من خلال الصيغة <code>map[key] = value</code>.
</p>

<h2>
	حذف عناصر من الرابطة
</h2>

<p>
	مثلما يمكنك إضافة أزواج قيمة-مفتاح إلى الرابطة أو تغيير قيمه، يمكنك أيضًا حذف العناصر الموجودة في الرابطة، فلإزالة زوج قيمة-مفتاح من الرابطة، استخدم الدالة <code>()delete</code> التي تحتوي على وسيطين، إذ يمثِّل الوسيط الأول الرابطة والثاني المفتاح:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_85" style=""><span class="kwd">delete</span><span class="pun">(</span><span class="typ">map</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">)</span></pre>

<p>
	لتكن لدينا الرابطة التالية التي تُعبّر عن الأذونات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_87" style=""><span class="pln">permissions </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="typ">int</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="str">"read"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln"> </span><span class="str">"write"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln"> </span><span class="str">"delete"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">:</span><span class="pln"> </span><span class="str">"create"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="str">"modify"</span><span class="pun">}</span></pre>

<p>
	الآن مثلًا لم تعُد بحاجة إلى إذن التعديل، لذا ستُزيله من الرابطة، ثم ستطبع الرابطة لتأكيد إزالتها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_89" style=""><span class="pln">permissions </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="typ">int</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="str">"read"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln"> </span><span class="str">"write"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln"> </span><span class="str">"delete"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">:</span><span class="pln"> </span><span class="str">"create"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">:</span><span class="pln"> </span><span class="str">"modify"</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">delete</span><span class="pun">(</span><span class="pln">permissions</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">permissions</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_91" style=""><span class="typ">map</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:</span><span class="pln">read </span><span class="lit">2</span><span class="pun">:</span><span class="pln">write </span><span class="lit">4</span><span class="pun">:</span><span class="kwd">delete</span><span class="pln"> </span><span class="lit">8</span><span class="pun">:</span><span class="pln">create</span><span class="pun">]</span></pre>

<p>
	يزيل السطر <code>(delete(permissions, 16</code> القيمة المرتبطة بالمفتاح 16 ضمن رابطة الأذونات ثم يُزيل المفتاح نفسه.
</p>

<p>
	إذا كنت ترغب في مسح الرابطة بجميع قيمها، فيمكنك إجراء ذلك عن طريق إسناد رابطة فارغة من النوع نفسه لها كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_93" style=""><span class="pln">permissions </span><span class="pun">=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">[</span><span class="typ">int</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">permissions</span><span class="pun">)</span></pre>

<p>
	سيُظهر الخرج أنّ الرابطة قد أصبحت فارغةً:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8691_95" style=""><span class="typ">map</span><span class="pun">[]</span></pre>

<p>
	بما أن الرابطة هي نوع بيانات قابل للتعديل mutable data type فيمكن التعديل عليها بالإضافة والحذف.
</p>

<h2>
	الخاتمة
</h2>

<p>
	ألقينا في هذا المقال نظرةً على الخرائط في جو، إذ تتألف الخرائط من أزواج قيمة-مفتاح، وتوفر حلًا ممتازًا لتخزين البيانات دون الحاجة إلى فهرستها، إذ يتيح لنا ذلك استرداد القيم بناءً على معانيها وعلاقتها بأنواع البيانات الأخرى.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-maps-in-go" rel="external nofollow">Understanding Maps inGo</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-boolean-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1847/" rel="">البيانات المنطقية Boolean في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1791/" rel="">تعرف على أنواع البيانات في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1865</guid><pubDate>Fri, 27 Jan 2023 16:08:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x646;&#x637;&#x642;&#x64A;&#x629; Boolean &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-boolean-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1847/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/184820449_--Boolean---Go-14.png.d18a42006968616eabaf6263c4c45b51.png" /></p>
<p>
	نوع البيانات المنطقي أو البولياني Boolean -واختصارًا bool نسبة إلى العالم George Boole- يمثَّل بتمثيل ثنائي فقط عادة صح true أو خطأ false أو 1 أو 0 أو يوجد ولا يوجد وهكذا، ويُستخدم هذا النوع في <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">البرمجة</a> بصورة كبيرة في عمليات المقارنة والتحكم بسير عمل البرنامج.
</p>

<p>
	يُمثَّل نوع البيانات هذا في لغة جو بالقيمة <code>false</code> والقيمة <code>true</code> مع ملاحظة أنه لابد من أن يكون أول محرف صغيرًا وليس كبيرًا، كما تغطي هذه المقالة الأساسيات التي ستحتاج إليها لفهم كيفية عمل نوع البيانات المنطقية بما في ذلك المقارنة المنطقية والعوامل المنطقية وجداول الحقيقة.
</p>

<h2>
	عوامل المقارنة
</h2>

<p>
	تُستخدَم عوامل المقارنة لمقارنة القيم وتقييّمها للحصول على قيمة منطقية واحدة إما صحيحة أو خاطئة، ويوضح الجدول أدناه عوامل المقارنة المنطقية:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				العامل
			</th>
			<th>
				توضيح
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				==
			</td>
			<td>
				المساواة
			</td>
		</tr>
		<tr>
			<td>
				=!
			</td>
			<td>
				عدم المساواة
			</td>
		</tr>
		<tr>
			<td>
				&gt;
			</td>
			<td>
				أصغر
			</td>
		</tr>
		<tr>
			<td>
				&lt;
			</td>
			<td>
				أكبر
			</td>
		</tr>
		<tr>
			<td>
				‎&lt;=‎
			</td>
			<td>
				أكبر أو يساوي
			</td>
		</tr>
		<tr>
			<td>
				=&lt;
			</td>
			<td>
				أصغر أو يساوي
			</td>
		</tr>
	</tbody>
</table>

<p>
	سنستخدِم العددين الصحيحين التاليين لتوضيح آلية عمل هذه المتغيرات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_10" style=""><span class="pln">x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
y </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">8</span></pre>

<p>
	من الواضح أنّ قيمة <code>x</code> أصغر من <code>y</code>، وسنستخدِم كل العوامل التي ذكرناها في الجدول السابق وسنرى خرج البرنامج مع كل حالة في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_12" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
    y </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">8</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x == y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">==</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x != y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">!=</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x &lt; y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x &gt; y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x &lt;= y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">&lt;=</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"x &gt;= y:"</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">&gt;=</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_14" style=""><span class="pln">x </span><span class="pun">==</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
x </span><span class="pun">!=</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
x </span><span class="pun">&lt;</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
x </span><span class="pun">&gt;</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
x </span><span class="pun">&lt;=</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
x </span><span class="pun">&gt;=</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span></pre>

<p>
	سألنا جو في الشيفرة أعلاه ما يلي:
</p>

<ul>
	<li>
		هل <code>x</code> تساوي <code>y</code>؟ والإجابة كانت <code>false</code> طبعًا.
	</li>
	<li>
		هل <code>x</code> لا تساوي <code>y</code>؟ والإجابة <code>true</code>.
	</li>
	<li>
		هل <code>x</code> أصغر من <code>y</code>؟ والإجابة <code>true</code>.
	</li>
	<li>
		هل <code>x</code> أكبر من <code>y</code>؟ والإجابة <code>false</code>.
	</li>
	<li>
		هل <code>x</code> أصغر أو يساوي <code>y</code>؟ والإجابة <code>true</code>.
	</li>
	<li>
		هل <code>x</code> أكبر أو يساوي <code>y</code>؟ والإجابة <code>false</code>.
	</li>
</ul>

<p>
	استخدَمنا الأعداد الصحيحة هنا، لكن يمكنك استخدام الأعداد العشرية أيضًا، كما يمكن أيضًا استخدام السلاسل النصية مع العوامل المنطقية، وتجدر الإشارة إلى أن مقارنة السلاسل حساسة لحالة المحارف، فالمحرف s لا يساوي المحرف S كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_16" style=""><span class="typ">Sammy</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">
sammy </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"sammy"</span><span class="pln">
alsoSammy </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy == sammy: "</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> sammy</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy == alsoSammy"</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> alsoSammy</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_21" style=""><span class="typ">Sammy</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> sammy</span><span class="pun">:</span><span class="pln">  </span><span class="kwd">false</span><span class="pln">
</span><span class="typ">Sammy</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> alsoSammy </span><span class="kwd">true</span></pre>

<p>
	لاحظ أنه عندما قارنا كلمة Sammy بكلمة sammy كان الخرج <code>false</code>؛ أما عندما قارنّا كلمة Sammy مع Sammy كان الخرج <code>true</code>، وبالتالي كما ذكرنا تكون مقارنة السلاسل النصية حساسةً لحالة المحارف.
</p>

<p>
	يمكنك أيضًا استخدام عوامل المقارنة الأخرى، مثل <code>&gt;</code> و <code>&lt;</code> لمقارنة السلاسل، وفي هذه الحالة ستقارن جو هذه السلاسل اعتمادًا على الترتيب المُعجمي lexicographically اعتمادًا على قيم ASCII للمحارف، كما يمكنك أيضًا تقييم القيم المنطقية باستخدام عوامل المقارنة، إذ سنختبر في المثال التالي فيما إذا كان المتغير المنطقي <code>t</code> الذي يحمل القيمة <code>true</code> لايساوي المتغير المنطقي <code>f</code> الذي يحمل القيمة <code>false</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_23" style=""><span class="pln">t </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
f </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"t != f: "</span><span class="pun">,</span><span class="pln"> t </span><span class="pun">!=</span><span class="pln"> f</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_25" style=""><span class="pln">t </span><span class="pun">!=</span><span class="pln"> f</span><span class="pun">:</span><span class="pln">  </span><span class="kwd">true</span></pre>

<p>
	انتبه إلى أن العامِل <code>=</code> يختلف عن العامِل <code>==</code>، إذ يُستخدَم الأول لعمليات الإسناد والثاني للاختبار المساواة، ويوضح المثال التالي الفرق، ففي الحالة الأولى نُسند قيمة <code>y</code> إلى <code>x</code> وفي السطر التالي نختبر مساواة <code>x</code> مع <code>y</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_28" style=""><span class="pln">x </span><span class="pun">=</span><span class="pln"> y   </span><span class="com">// إسناد قيمة المتغير اليميني إلى المتغير اليساري</span><span class="pln">
x </span><span class="pun">==</span><span class="pln"> y  </span><span class="com">// تقييم نتيجة المساواة بين المتغيرين</span></pre>

<h2>
	العوامل المنطقية
</h2>

<p>
	يوجد نوعان من العوامل المنطقية في الجبر المنطقي والمستخدَمان لتحديد العلاقة بين المتغيرات هما and و or، إضافةً إلى عامل النفي not، إذ يرمَز في لغة جو للعامل المنطقي and بالرمز <code>&amp;&amp;</code> وللعامل or بالرمز <code>||</code> وللعامل not بالرمز <code>!</code> كما يلي:
</p>

<ul>
	<li>
		<code>x &amp;&amp; y</code> تعني أنه إذا كان كل من <code>x</code> و <code>y</code> مٌحققان أي كلاهما <code>true</code>، فسيكون الناتج <code>true</code> وإلا فسيكون <code>false</code>.
	</li>
	<li>
		<code>x || y</code> تعني أنه إذا كان أحدهما <code>true</code>، فسيكون الناتج <code>true</code>.
	</li>
	<li>
		<code>x!</code> تعني أنه إذا كانت <code>x</code> قيمتها <code>true</code>، فسيكون الخرج <code>false</code>، وإذا كانت <code>false</code> فسيكون الخرج <code>true</code>.
	</li>
</ul>

<p>
	كثيرًا ماتُستخدَم هذه العوامل في البرمجة ولا سيما عند محاولة اختبار تعابير متعددة أو شروط متعددة، فإذا كنت مثلًا تبني برنامجًا يُحدِّد فيما إذا كان الطالب ناجحًا أم لا في إحدى المواد الجامعية، فيجب أن يكون الطالب قد حضر 4 جلسات عمليّة على الأقل <code>x</code>، ويجب أن يحصل على 40% من درجة الامتحان العملي على الأقل <code>y</code> و60% من درجة الامتحان (النظري + العملي) على الأقل <code>z</code>، أي لدينا 3 متغيرات <code>x y z</code> ويجب أن تتحقق كلها، أي <code>x &amp;&amp; y &amp;&amp; z</code>، ولنرى مثالًا عن استخدام هذه العوامل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_30" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">((</span><span class="lit">9</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">7</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">4</span><span class="pun">))</span><span class="pln">   </span><span class="com">// التعبيران محققان</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">((</span><span class="lit">8</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">(</span><span class="lit">6</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">))</span><span class="pln"> </span><span class="com">// التعبير الأول صحيح فقط</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(!(</span><span class="lit">3</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">))</span><span class="pln">            </span><span class="com">// التعبير خاطئ، لكن مع النفي يصبح صحيح</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_32" style=""><span class="kwd">true</span><span class="pln">
</span><span class="kwd">true</span><span class="pln">
</span><span class="kwd">true</span></pre>

<p>
	لدينا في السطر الأول <code>((fmt.Println((9 &gt; 7) &amp;&amp; (2 &lt; 4</code>، نلاحظ أنّ 9 أكبر من 7 و 2 أصغر من 4، وبالتالي فإن طرفَي العلاقة محققان، وبالتالي سيطبع true، وفي السطر الثاني <code>((fmt.Println((8 == <span class="ipsEmoji">?</span> || (6 != 6</code> نلاحظ أنّ 8 تساوي 8 مُحققة، لكن 6 لا تساوي 6 غير مُحققة ولكن مع ذلك سيطبع <code>true</code>، لأنه في حالة العامل المنطقي <code>||</code> يكفي أن يكون أحد طرفَي العلاقة محققًا؛ أما في السطر الأخير <code>((fmt.Println(!(3 &lt;= 1</code>، فنلاحظ أنّ <code>1=&lt;3</code> تقييمها <code>false</code>، لكن بما أننا نستخدِم معامل النفي، فسيكون الخرج هو الحالة المعاكسة، أي <code>true</code>.
</p>

<p>
	لا يختلف المثال التالي عما سبق إلا في نوع البيانات، إذ سنستخدِم نوع البيانات العشرية بدل الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_34" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">((-</span><span class="lit">0.2</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1.4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.8</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3.1</span><span class="pun">))</span><span class="pln">  </span><span class="com">// تعبير واحد فقط صحيح</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">((</span><span class="lit">7.5</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">8.9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9.2</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">9.2</span><span class="pun">))</span><span class="pln"> </span><span class="com">// التعبيران خاطئان</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(!(-</span><span class="lit">5.7</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0.3</span><span class="pun">))</span><span class="pln">               </span><span class="com">// التعبير صحيح ولكن يصبح مع النفي خاطئًا</span></pre>

<p>
	يمكنك أيضًا كتابة تعليمات مركبة باستخدام <code>&amp;&amp;</code> و <code>||</code> و <code>!</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_36" style=""><span class="pun">!((-</span><span class="lit">0.2</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1.4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">((</span><span class="lit">0.8</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3.1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0.1</span><span class="pun">)))</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_38" style=""><span class="kwd">true</span></pre>

<p>
	نلاحظ أن نتيجة التركيب <code>(0.8 &lt; 3.1) || (0.1 == 0.1)</code> هي <code>true</code> فكلا الطرفَين محققَين، لكن نلاحظ أنّ الطرف <code>(-0.2 &gt; 1.4)</code> غير محقق، أي تقييمه <code>false</code>، وبالتالي سيكون خرج التركيب السابق بأكمله هو <code>false</code>، وبما أنه لدينا إشارة النفي، فسيكون الخرج هو <code>true</code>.
</p>

<p>
	أي باختصار، العوامل المنطقية <code>&amp;&amp;</code> و <code>||</code> و <code>!</code> تقيم تعبيرات ثم تعيد قيمة منطقية ناتجة عن تقييمها.
</p>

<h2>
	جداول الحقيقة
</h2>

<p>
	لتعزيز قدراتك البرمجية لا بدّ أن يكون لديك القليل من الفهم عن الفرع المنطقي للرياضيات، وفيما يلي جداول الحقيقة لعامل المقارنة <code>==</code>، ولكل من العوامل المنطقية <code>&amp;&amp;</code>، <code>||</code> و <code>!</code>. ويفضل أن تحفظها، لتصبح راسخة في ذهنك إذ ستسرع من عملية اتخاذ القرار البرمجي لديك:
</p>

<ul>
	<li>
		جدول الحقيقة لعامِل المقارنة <code>==</code>:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th>
				x
			</th>
			<th>
				==
			</th>
			<th>
				y
			</th>
			<th>
				الخرج
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				true
			</td>
			<td>
				==
			</td>
			<td>
				true
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				true
			</td>
			<td>
				==
			</td>
			<td>
				false
			</td>
			<td>
				false
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				==
			</td>
			<td>
				true
			</td>
			<td>
				false
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				==
			</td>
			<td>
				false
			</td>
			<td>
				true
			</td>
		</tr>
	</tbody>
</table>

<ul>
	<li>
		جدول الحقيقة للعامِل المنطقي and أو <code>&amp;&amp;</code>:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th>
				x
			</th>
			<th>
				and
			</th>
			<th>
				y
			</th>
			<th>
				الخرج
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				true
			</td>
			<td>
				and
			</td>
			<td>
				true
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				true
			</td>
			<td>
				and
			</td>
			<td>
				false
			</td>
			<td>
				false
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				and
			</td>
			<td>
				true
			</td>
			<td>
				false
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				and
			</td>
			<td>
				false
			</td>
			<td>
				false
			</td>
		</tr>
	</tbody>
</table>

<ul>
	<li>
		جدول الحقيقة للعامِل المنطقي or أو <code>||</code>:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th>
				x
			</th>
			<th>
				or
			</th>
			<th>
				y
			</th>
			<th>
				الخرج
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				true
			</td>
			<td>
				or
			</td>
			<td>
				true
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				true
			</td>
			<td>
				or
			</td>
			<td>
				false
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				or
			</td>
			<td>
				true
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				false
			</td>
			<td>
				or
			</td>
			<td>
				false
			</td>
			<td>
				false
			</td>
		</tr>
	</tbody>
</table>

<ul>
	<li>
		جدول الحقيقة للعامِل المنطقي not أو <code>!</code>:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th>
				not
			</th>
			<th>
				x
			</th>
			<th>
				الخرج
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				not
			</td>
			<td>
				false
			</td>
			<td>
				true
			</td>
		</tr>
		<tr>
			<td>
				not
			</td>
			<td>
				true
			</td>
			<td>
				false
			</td>
		</tr>
	</tbody>
</table>

<h2>
	استخدام العوامل المنطقية للتحكم بسير عمل البرنامج
</h2>

<p>
	يمكنك استخدام العوامل المنطقية أو عوامل المقارنة للتحكم بسير عمل البرنامج من خلال استخدامها مع جمل الشرط <code>if .. else</code>، فعند تحقق شرط ما يتخذ البرنامج إجراءً محددًا استجابةً لذلك عند تلك النقطة، أي إذا تحقق هذا افعل هذا وإلا لا تفعل وتابع فيما كنت تفعله، ويوضح المثال التالي هذا الأمر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4269_40" style=""><span class="kwd">if</span><span class="pln"> grade </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">65</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                 </span><span class="com">// شرط Condition</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Passing grade"</span><span class="pun">)</span><span class="pln"> </span><span class="com">// بند Clause</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Failing grade"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	المقصود من الشيفرة أنه إذا كانت درجة الطالب أكبر أوتساوي 65، فاطبع أنه ناجح، وإلا اطبع أنه راسب، أي إذا كانت درجة الطالب 83 مثلًا، فسيطبع Passing grade وإذا كانت 59 سيطبع Failing grade.
</p>

<h2>
	الخاتمة
</h2>

<p>
	استعرضنا في هذا المقال العوامِل المنطقية وعوامل المقارنة التي تُستخدم في الجبر المنطقي وفي العديد من التطبيقات في عالم البرمجة، كما تعرّفنا أيضًا على جداول الحقيقة وأظهرنا كيفية استخدام العوامل المنطقية وعوامل المقارنة في التحكم في سير عمل البرنامج.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/understanding-boolean-logic-in-go" rel="external nofollow">Understanding Boolean Logic inGo</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1846/" rel="">العمليات الحسابية في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1845/" rel="">تحويل أنواع البيانات في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1847</guid><pubDate>Wed, 18 Jan 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x645;&#x644;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62D;&#x633;&#x627;&#x628;&#x64A;&#x629; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1846/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/2055854191_-----Go-13.png.661a1c9a751fd8018057cdfe3a7fb9f1.png" /></p>
<p>
	تُعَدّ الأعداد شائعةً في <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">البرمجة</a>، إذ تُستخدَم لتمثيل أشياء مثل أبعاد حجم الشاشة والمواقع الجغرافية والمال والنقاط ومقدار الوقت الذي مضى في الفيديو ومواضع الصور ضمن الألعاب والألوان من خلال ربطها مع الأرقام …إلخ، كما يرتبط الأداء الفعال في العديد من البرامج ارتباطًا وثيقًا بكيفية إنجاز العمليات الحسابية، لذا تُعَدّ أمرًا مهمًا عليك إتقانه، كما ستجعل منك براعتك في الرياضيات مبرمجًا أفضل لكنها ليست شرطًا أساسيًا، فإذا لم يكن لديك خلفية في الرياضيات، فحاول التفكير في الرياضيات بوصفها أداةً لتحقيق ما ترغب في تحقيقه وطريقةً لتحسين تفكيرك المنطقي.
</p>

<p>
	سنعمل مع أهم نوعين من الأعداد المستخَدمة في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> وهما الأعداد الصحيحة والعشرية:
</p>

<ul>
	<li>
		الأعداد الصحيحة: هي أعداد سالبة أو موجبة مثل 1, 0, 1-, … إلخ.
	</li>
	<li>
		الأعداد العشرية هي التي تحتوي فواصل عشرية مثل 9.0, 2.25-, … إلخ.
	</li>
</ul>

<h2>
	العوامل الرياضية
</h2>

<p>
	العامل operator هو رمز يمثل عملية وغالبًا ما تكون عملية رياضية، فمثلًا العامل + يمثل عملية الجمع الرياضية.
</p>

<p>
	نستعرض في الجدول التالي أهم العوامل المستخدَمة في لغة جو والتي سنتطرق لها في هذا المقال، ويمكنك ملاحظة أنّ أغلب هذه العوامل مألوفة لديك من خلال دراستك للرياضيات وبعضها غير مألوف.
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				العملية
			</th>
			<th>
				الوظيفة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				x + y
			</td>
			<td>
				جمع العددين x و y
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x - y
			</td>
			<td>
				طرح العددين x و y
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x * y
			</td>
			<td>
				ضرب العددين x و y
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x / y
			</td>
			<td>
				قسمة العددين x و y
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x % y
			</td>
			<td>
				باقي قسمة x على y
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x+
			</td>
			<td>
				ضرب قيمة المتغير بالعدد +1
			</td>
		</tr>
		<tr>
			<td>
				--------
			</td>
			<td>
				--------
			</td>
		</tr>
		<tr>
			<td>
				x-
			</td>
			<td>
				ضرب قيمة المتغير بالعدد -1
			</td>
		</tr>
	</tbody>
</table>

<p>
	سيغطي المقال أيضًا العوامل المركبة التي تكون إحدى مركباتها عامل حسابي مع إشارة اليساوي مثل <code>=+</code> و <code>=*</code>.
</p>

<h2>
	الجمع والطرح
</h2>

<p>
	يمكنك إنجاز عمليات الجمع والطرح في لغة جو تمامًا مثل استخدامك للآلة الحاسبة كما في المثال التالي من أجل الأعداد الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_6" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_8" style=""><span class="lit">6</span></pre>

<p>
	يمكنك تهيئة متغيرات تُخزّن تلك القيم ثم تطبع نتيجة جمعها بدلًا من تمرير الأعداد مباشرةً إلى دالة الطباعة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_10" style=""><span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">88</span><span class="pln">
b </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">103</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_12" style=""><span class="lit">191</span></pre>

<p>
	قد يكون العدد الصحيح سالبًا، ففي هذه الحالة نضع إشارة سالب قبله بكل بساطة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_16" style=""><span class="pln">c </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">36</span><span class="pln">
d </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">25</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">c </span><span class="pun">+</span><span class="pln"> d</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_14" style=""><span class="pun">-</span><span class="lit">11</span></pre>

<p>
	الأمر نفسه بالنسبة للأعداد العشرية، إذ يمكنك إنجاز عمليات الجمع كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_19" style=""><span class="pln">e </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5.5</span><span class="pln">
f </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">2.5</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">e </span><span class="pun">+</span><span class="pln"> f</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_21" style=""><span class="lit">8</span></pre>

<p>
	لاحظ أن الناتج هو عدد بدون فاصلة عشرية، إذ منوقع أنّ الخرج يحتوي على فاصلة عشرية بما أنّ عملية الجمع بين عددين عشريين أي 8.0، والسبب في ذلك هو أن دالة الطباعة تحوِّل الخرج تلقائيًا إلى قيمة صحيحة من خلال إسقاط الفواصل العشرية، ولتجنب حدوث ذلك نستخدِم العنصر النائب <code>2f.%</code>، إذ تشير <code>f</code> إلى وجود عدد حقيقي و<code>2</code> إلى إبقاء عددين بعد الفاصلة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_23" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%.2f"</span><span class="pun">,</span><span class="pln"> e </span><span class="pun">+</span><span class="pln"> f</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_25" style=""><span class="lit">8.00</span></pre>

<p>
	عملية الطرح نفسها كما في الجمع مع استبدال العامل <code>+</code> بالعامل <code>-</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_27" style=""><span class="pln">g </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">75.67</span><span class="pln">
h </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">32.0</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">g </span><span class="pun">-</span><span class="pln"> h</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_32" style=""><span class="lit">43.67</span></pre>

<p>
	لا يمكنك في لغة جو إنجاز عملية حسابية بين عددين من نوعي بيانات مختلفين مثل <code>int</code> و <code>float64</code> كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_35" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
j </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">7.0</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> j</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج إشعارًا بعدم تطابق نوعي البيانات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_38" style=""><span class="pln">i </span><span class="pun">+</span><span class="pln"> j </span><span class="pun">(</span><span class="pln">mismatched types </span><span class="typ">int</span><span class="pln"> and </span><span class="typ">float64</span><span class="pun">)</span></pre>

<h2>
	العمليات الحسابية الأحادية
</h2>

<p>
	يتكون التعبير الرياضي الأحادي Unary Arithmetic Operation من مكوِّن أو عنصر واحد فقط، إذ يمكننا في لغة جو استخدام علامتَي الجمع والطرح على أساس عنصر أحادي مُقترن بقيمة، ولتبسيط الأمر، يُعَدّ إشارة <code>+</code> أو <code>-</code> تتلو قيمة أو متغير (كأنما نضرب -1 أو +1 بمتغير). ستوضّح الأمثلة أكثر:
</p>

<p>
	تشير علامة الجمع على الرغم من عدم استخدامها بصورة شائعة إلى هوية القيمة identity، ويمكننا استخدامها مع القيم الموجبة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_40" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">3.3</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(+</span><span class="pln">i</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_42" style=""><span class="lit">3.3</span></pre>

<p>
	عند استخدام إشارة الجمع مع عدد سالب، فلن تتغير إشارة هذا العدد، أي سيبقى سالبًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_44" style=""><span class="pln">j </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">19</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(+</span><span class="pln">j</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_46" style=""><span class="pun">-</span><span class="lit">19</span></pre>

<p>
	هنا المتغير موجب، ثم في دالة الطباعة اسبقناه بالإشارة <code>-</code>، وبالتالي تتبدّل إشارته من موجب إلى سالب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_48" style=""><span class="pln">k </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">3.3</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(-</span><span class="pln">k</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_51" style=""><span class="lit">3.3</span><span class="pun">-</span></pre>

<p>
	وبصورة بديلة عند استخدام العامل الأحادي سالب الإشارة مع قيمة سالبة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_53" style=""><span class="pln">j </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">19</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(-</span><span class="pln">j</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_57" style=""><span class="lit">19</span></pre>

<p>
	الهدف من استخدام العملية الأحادية <code>+</code> والعملية الأحادية <code>-</code> هو إعادة هوية القيمة أو الإشارة المعاكسة لقيمة.
</p>

<h2>
	الضرب والقسمة
</h2>

<p>
	كما فعلنا في عمليات الجمع والطرح، لكن نستخدِم هنا عوامل مختلفة هي <code>*</code> للضرب و <code>/</code> للقسمة، وفيما يلي مثال عن عملية الضرب بين عددين عشريين:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_59" style=""><span class="pln">k </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">100.2</span><span class="pln">
l </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">10.2</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">k </span><span class="pun">*</span><span class="pln"> l</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_61" style=""><span class="lit">1022.04</span></pre>

<p>
	بالنسبة للقسمة يجب عليك معرفة أنّ الناتج قد يختلف تبعًا لنوع البيانات المختلفة، ففي حال قسّمت أعدادًا صحيحةً، فسيكون ناتج القسمة عددًا صحيحًا أيضًا، إذ ستُسقط أية فواصل عشرية إذا وجدت.
</p>

<p>
	سنقسّم في المثال التالي عددين صحيحين 80/6 كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_63" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    m </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">80</span><span class="pln">
    n </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">6</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">m </span><span class="pun">/</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_65" style=""><span class="lit">13</span></pre>

<p>
	لاحظ إسقاط الفاصلة العشرية من الخرج، فإذا أردت إبقاء الأعداد بعد الفاصلة، فعليك استخدام النوع العشري مع هذه البيانات عبر تحويلها باستخدام <code>float32()‎</code> أو <code>float64()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_67" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    s </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">80</span><span class="pln">
    t </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
    r </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">float64</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">float64</span><span class="pun">(</span><span class="pln">t</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">r</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_69" style=""><span class="lit">13.333333333333334</span></pre>

<h2>
	باقي القسمة
</h2>

<p>
	يمكنك إيجاد باقي قسمة عدد على عدد آخر من خلال العامل <code>%</code>، وهذا مفيد جدًا في الكثير من الحالات مثل إيجاد مضاعفات الأعداد، فلنلق نظرةً على المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_71" style=""><span class="pln">o </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">85</span><span class="pln">
p </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">15</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">o </span><span class="pun">%</span><span class="pln"> p</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_73" style=""><span class="lit">10</span></pre>

<p>
	ناتج قسمة 85 على 15 هو 55 والباقي 10، لذا سيُخرج البرنامج العدد 10، وإذا أردت إيجاد باقي القسمة في حالة الأعداد العشرية، فيمكنك استخدام الدالة <code>()Mod</code> من الحزمة <code>math</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_75" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"math"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    q </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">36.0</span><span class="pln">
    r </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">8.0</span><span class="pln">

    s </span><span class="pun">:=</span><span class="pln"> math</span><span class="pun">.</span><span class="typ">Mod</span><span class="pun">(</span><span class="pln">q</span><span class="pun">,</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_77" style=""><span class="lit">4</span></pre>

<h2>
	ترتيب العمليات الحسابية
</h2>

<p>
	كما في الرياضيات، علينا أن نضع في الحسبان أن العوامل تُطبّق حسب الأولوية وليس من اليسار إلى اليمين أو من اليمين إلى اليسار، فإذا نظرت إلى التعبير الرياضي التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_80" style=""><span class="pln">u </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5</span></pre>

<p>
	هنا يُطبق الضرب أولًا ثم ناتج الضرب 50 يُجمع مع 10 لأن الأولوية للضرب على الجمع أو الطرح ويكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_82" style=""><span class="lit">60</span></pre>

<p>
	استخدم الأقواس إذا أردت مثلًا جمع 10 مع 10 أولًا لأن ما بين الأقواس له الأولوية على ما هو خارجها، أي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_84" style=""><span class="pln">u </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">(</span><span class="lit">10</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_86" style=""><span class="lit">100</span></pre>

<p>
	ترتيب إجراء العمليات الحسابية هو كما يلي:
</p>

<p>
	الأقواس Parentheses &gt; الأس Exponent&gt; الضرب Multiplication&gt; القسمة Division&gt; الجمع Addition&gt; الطرح Subtraction.
</p>

<p>
	ويمكن اختصار أوائل كلمات تلك العمليات بالبيت التالي: "قم أبعد ضيقًا … قم جد طريقًا".
</p>

<h2>
	عوامل الإسناد
</h2>

<p>
	من المألوف لديك استخدام عامل المساواة <code>=</code> لإسناد قيمة إلى متغير مثل إسناد القيمة 10 إلى المتغير <code>x</code> بكتابة <code>x=10</code>، كما يمكنك جعل الأمر أكثر إثارةً من خلال إدخال العمليات الحسابية إلى هذه المعادلة، إذ يمكنك استخدام العامل <code>+</code> أو <code>-</code> أو <code>*</code> أو <code>/</code> مع العامل السابق لتطبيق عمليات حسابية محددة، فإذا كان لديك مثلًا متغير <code>x</code> قيمته 5 وأردت جعل قيمته 7، فيمكنك كتابة <code>x += 2</code> وهذا يكافئ كتابة <code>x = x+2</code>، وبالتالي تصبح قيمة <code>x</code> تساوي 7، أو يمكنك ضرب قيمة <code>x</code> بالقيمة 3 من خلال كتابة <code>x *= 3</code> وهذا يكافئ <code>x = x*3</code> أو يمكنك استخدام عامل باقي القسمة أيضًا <code>x %= 2</code> والذي يكافئ <code>x = x%2</code> وهكذا بالنسبة لباقي العمليات، ويوضّح المثال التالي الأمر أكثر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_88" style=""><span class="pln">w </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
w </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_90" style=""><span class="lit">6</span></pre>

<p>
	تُستخدَم عوامل الإسناد المركبة كثيرًا في حالة حلقات <code>for</code> والتي ستستخدِمها عندما تريد تكرار عملية عدة مرات كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_92" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    values </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> x </span><span class="pun">:=</span><span class="pln"> range values </span><span class="pun">{</span><span class="pln">

        w </span><span class="pun">:=</span><span class="pln"> x

        w </span><span class="pun">*=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">

        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_94" style=""><span class="lit">0</span><span class="pln">
</span><span class="lit">2</span><span class="pln">
</span><span class="lit">4</span><span class="pln">
</span><span class="lit">6</span><span class="pln">
</span><span class="lit">8</span><span class="pln">
</span><span class="lit">10</span><span class="pln">
</span><span class="lit">12</span></pre>

<p>
	استخدمنا حلقة <code>for</code> في المثال أعلاه للتكرار على الشريحة <code>values</code>، إذ هيّأنا المتغير <code>w</code> في كل تكرار بقيمة <code>x</code> الحالية ثم ضربناها بالقيمة 2 وطبعنا الخرج.
</p>

<p>
	تمتلك لغة جو عامل إسناد مركب لكل عامل رياضي، وقد ناقشنا ذلك في هذا المقال، فلإضافة 1 إلى المتغير نفسه ثم إسناد القيمة الجديدة للمتغير نفسه، نكتب ما يلي والتي تكافئ <code>y=y+1</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_96" style=""><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	طرح 1 ثم إسناد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_98" style=""><span class="pln">y </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	ضرب بالعدد 2 ثم إسناد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_103" style=""><span class="pln">y </span><span class="pun">*=</span><span class="pln"> </span><span class="lit">2</span></pre>

<p>
	قسمة على العدد 3 ثم إسناد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_106" style=""><span class="pln">y </span><span class="pun">/=</span><span class="pln"> </span><span class="lit">3</span></pre>

<p>
	باقي قسمة المتغير على العدد 3 ثم إسناد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3148_109" style=""><span class="pln">y </span><span class="pun">%=</span><span class="pln"> </span><span class="lit">3</span></pre>

<p>
	تُعَدّ عوامل الإسناد المركبة مفيدةً عندما تحتاج إلى زيادة أو تقليل قيمة المتغيرات تدريجيًا أو عندما تحتاج إلى أتمتة عمليات معينة في برنامجك.
</p>

<h2>
	الخاتمة
</h2>

<p>
	ناقشنا في هذا المقال العديد من العوامل التي يمكنك استخدامها في لغة جو مع أنواع البيانات العددية الصحيحة والعشرية، كما يمكنك الاطلاع على المقالات السابقة من سلسلة <a href="https://academy.hsoub.com/tags/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%20%D8%A8%D9%84%D8%BA%D8%A9%20go/" rel="">البرمجة بلغة Go</a> لمزيد من التفاصيل عن المتغيرات والتعامل مع البيانات في لغة جو.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-do-math-in-go-with-operators" rel="external nofollow">How To Do Math in GowithOperators</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1845/" rel="">تحويل أنواع البيانات في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1846</guid><pubDate>Sat, 14 Jan 2023 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62D;&#x648;&#x64A;&#x644; &#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1845/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1643791803_------Go-12.png.6bcc7efef02deecad2788b20a9ec8328.png" /></p>
<p>
	تُستخدَم أنواع البيانات في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> للإشارة إلى نوع معيَّن من البيانات وتحديد القيم التي يمكنك إسنادها لذلك النوع والعمليات التي يمكنك إجراؤها عليها، فهناك أوقات نحتاج إلى تحويل القيم من نوع إلى آخر لمعالجتها بطريقة مختلفة، فقد نحتاج مثلًا إلى وصل القيم العددية بالسلاسل النصية أو إظهار الفواصل العشرية لأعداد صحيحة، وغالبًا ما تُعامَل البيانات التي يُدخلها المستخدِم في جو على أنها سلاسل نصية، حتى إذا تضمنت أعدادًا، وبالتالي يتوجب عليك تحويلها إلى بيانات عددية إذا أردت إدخالها في عمليات حسابية.
</p>

<p>
	تُعَدّ جو لغةً ثابتةً تتطّلب تحديد النوع statically typed language، لذا تكون أنواع البيانات مرتبطةً بالمتغيرات وليس بالقيم، أي في حال كان لديك متغير من النوع <code>int</code>، فلا يمكن أن يُسنَد إليه متغير من نوع آخر، وسيرشدك هذا المقال إلى كيفية تحويل الأعداد والسلاسل النصية، بالإضافة إلى تقديم بعض الأمثلة التوضيحية.
</p>

<h2>
	تحويل الأنواع العددية
</h2>

<p>
	هناك نوعان رئيسيان من البيانات العددية في جو وهما الأعداد الصحيحة والأعداد العشرية. ستعمل في بعض الأحيان على شيفرة برمجية كتبها شخص آخر، وقد تحتاج إلى تحويل عدد صحيح إلى عدد عشري أو العكس، أو قد تجد أنك تستخدم عددًا صحيحًا في الوقت الذي تحتاج إلى أعداد عشرية، لذلك تتوفر في جو توابع مضمّنة تُسهِّل عليك التحويل بين الأنواع العددية.
</p>

<h3>
	التحويل بين أنواع الأعداد الصحيحة
</h3>

<p>
	تتضمن جو العديد من أنواع البيانات الصحيحة التي يمكنك التبديل بينها حسب الحاجة ومتطلبات الأداء أو لأسباب أخرى، فيُنشئ جو في بعض الأحيان مثلًا قيمًا عدديةً من النوع <code>int</code> تلقائيًا، وبالتالي في حال أدخلت أعدادًا من النوع <code>int64</code>، فلن تتمكن استخدام العدد السابق الذي ولدته جو مع العدد الذي أدخلته ضمن تعبير رياضي واحد لأنهما من نوعين مختلفين.
</p>

<p>
	افترض أنه لديك متغير من النوع <code>int8</code> وتحتاج إلى تحويله إلى <code>int32</code>، فيمكنك إجراء ذلك عن طريق استخدام الدالة <code>int32()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_9" style=""><span class="pln">var index </span><span class="typ">int8</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">15</span><span class="pln">

var bigIndex </span><span class="typ">int32</span><span class="pln">

bigIndex </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int32</span><span class="pun">(</span><span class="pln">index</span><span class="pun">)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">bigIndex</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_11" style=""><span class="lit">15</span></pre>

<p>
	عرّفنا متغير <code>index</code> من النوع <code>int8</code> ومتغير <code>bigIndex</code> من النوع <code>int32</code> ثم حوّلنا نوع المتغير <code>index</code> إلى النوع <code>int32</code> وخزّنا النتيجة في المتغير <code>bigIndex</code> ثم طبعنا قيمته، وللتأكد من عملية التحويل أو لتفقّد نوع البيانات لأحد المتغيرات، استخدم العنصر النائب <code>T%</code> مع دالة الطباعة <code>fmt.Printf</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_13" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"index data type:    %T\n"</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"bigIndex data type: %T\n"</span><span class="pun">,</span><span class="pln"> bigIndex</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_15" style=""><span class="pln">index data type</span><span class="pun">:</span><span class="pln">  </span><span class="typ">int8</span><span class="pln">
bigIndex data type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">int32</span></pre>

<p>
	لاحظ أنه يطبع نوع البيانات للمتغير وليس قيمته.
</p>

<p>
	يمكنك أيضًا التحويل من نوع بيانات كبير إلى نوع أصغر مثل تحويل من <code>int64</code> إلى <code>int8</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_17" style=""><span class="pln">var big </span><span class="typ">int64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">64</span><span class="pln">

var little </span><span class="typ">int8</span><span class="pln">

little </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int8</span><span class="pun">(</span><span class="pln">big</span><span class="pun">)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">little</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_19" style=""><span class="lit">64</span></pre>

<p>
	لكن انتبه إلى أنه عند التحويل من نوع أكبر إلى نوع أصغر قد تتجاوز القيمة الأكبر بالقيمة المطلقة التي يمكن لهذا النوع تخزينها، ففي حال تجاوزت القيمة تلك، فستحدث عملية التفاف wraparound كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_21" style=""><span class="pln">var big </span><span class="typ">int64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">129</span><span class="pln">
var little </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int8</span><span class="pun">(</span><span class="pln">big</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">little</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_23" style=""><span class="pun">-</span><span class="lit">127</span></pre>

<p>
	أكبر قيمة يمكن أن يخزنها متغير من النوع <code>int8</code> هي 127 وأصغر قيمة -127، فإذا تجاوزتها، فسيحدث التفاف، وبما أنّ 129 في المثال السابق أكبر من القيمة العظمى التي يمكن للنوع المحدد تخزينه، فقد حدث التفاف إلى القيمة الأصغر، أي حوّله إلى أصغر قيمة ممكنة فيه.
</p>

<h2>
	تحويل الأعداد الصحيحة إلى أعداد عشرية
</h2>

<p>
	الأمر مشابه لعمليات التحويل التي أجريناها منذ قليل، إذ سنستخدِم هنا الدالة <code>float64()‎</code> أو <code>float32()‎</code> لإجراء عمليات التحويل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_25" style=""><span class="pln">var x </span><span class="typ">int64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">57</span><span class="pln">

var y </span><span class="typ">float64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">float64</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%.2f\n"</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_27" style=""><span class="lit">57.00</span></pre>

<p>
	لاحظ أننا حوّلنا نوع المتغير <code>x</code> ذو القيمة الابتدائية <code>57</code> من <code>int64</code> إلى <code>float64</code>، وبالتالي أصبحت<code>57.00</code>، أخيرًا استخدمنا العنصر النائب <code>‎%.2f</code> ضمن دالة الطباعة للإشارة إلى عدد عشري مع الإبقاء على رقمين بعد الفاصلة.
</p>

<p>
	وبذلك يمكنك استخدام <code>float32()‎</code> أو <code>float64()‎</code> لتحويل الأعداد العشرية إلى أعداد صحيحة.
</p>

<h2>
	تحويل الأعداد العشرية إلى أعداد صحيحة
</h2>

<p>
	يمكنك تحويل الأعداد العشرية إلى أعداد صحيحة باستخدام الدوال نفسها التي استخدمناها سابقًا عند التحويل بين أنواع الأعداد الصحيحة، ولكن انتبه إلى أنّ تغير النوع من عشري إلى صحيح سيفقدك الأعداد الموجودة بعد الفاصلة (الأجزاء العشرية أي الأرقام التي بعد الفاصلة العشرية)، وبالتالي قد تؤثر على دقة الحالة أو العملية كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_29" style=""><span class="pln">var f </span><span class="typ">float64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">390.8</span><span class="pln">
var i </span><span class="typ">int</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"f = %.2f\n"</span><span class="pun">,</span><span class="pln"> f</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"i = %d\n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_31" style=""><span class="pln">f </span><span class="pun">=</span><span class="pln"> </span><span class="lit">390.80</span><span class="pln">
i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">390</span></pre>

<p>
	عرّفنا في المثال السابق متغير <code>f</code> من النوع العشري وهيأناه بقيمة <code>390.8</code> ثم عرّفنا متغير <code>i</code> من النوع الصحيح وهيّأناه بقيمة المتغيّر <code>f</code> بعد تحويّله إلى النوع الصحيح من خلال الدالة <code>int</code> ثم طبعنا قيمتهما، ولاحظ أنه عندما حوّلنا القيمة <code>390.8</code> إلى <code>390</code>، أُسقطت القيمة الموجودة بعد الفاصلة، وتجدر الملاحظة إلى أنّ جو لا تُقرِّب العدد؛ وإنما تهمل كل الأعداد بعد الفاصلة فقط.
</p>

<p>
	ولنأخذ المثال التالي الذي يُعرِّف المتغير <code>b</code> ويعطيه القيمة <code>125.0</code> والمتغير <code>c</code> مع القيمة <code>390.8</code> ثم يطبعهما على شكل عدد صحيح:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_78" style=""><span class="pln">b </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">125.0</span><span class="pln">
c </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">390.8</span><span class="pln">

fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="typ">int</span><span class="pun">(</span><span class="pln">b</span><span class="pun">))</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="typ">int</span><span class="pun">(</span><span class="pln">c</span><span class="pun">))</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_34" style=""><span class="lit">125</span><span class="pln">
</span><span class="lit">390</span></pre>

<p>
	عند تحويل عدد عشري إلى عدد صحيح باستعمال <code>int()‎</code>، تقتص لغة Go الأعداد العشرية وتبقي على العدد الصحيح فقط، وانتبه أننا قلنا "تقتص" أي أنها تزيل الفواصل العشرية دون إجراء عملية تقريب، فلن يُقرَّب العدد <code>390.8</code> إلى <code>391</code> بل سيصبح بعد التحويل <code>390</code>.
</p>

<h3>
	تحويل الأعداد عبر القسمة
</h3>

<p>
	تُسقط جو الفواصل إذا وُجِدت أيضًا عند تقسيم على آخر صحيح:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_81" style=""><span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_83" style=""><span class="lit">2</span></pre>

<p>
	إذا كان أحد الأعداد في عملية القسمة من النوع العشري float، فستُعَدّ كل الأعداد عشريةً وكذلك الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_85" style=""><span class="pln">  a </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5.0</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_87" style=""><span class="lit">2.5</span></pre>

<p>
	كما تلاحظ لم تُسقَط الأعداد بعد الفاصلة هذه المرة.
</p>

<h2>
	تحويلات السلاسل النصية
</h2>

<p>
	تُعَدّ السلسلة النصية تسلسلًا مؤلفًا من محرف واحد أو أكثر، ويمكن أن يكون المحرف حرفًا أبجديًا أو عددًا أو رمزًا، وتُعَدّ السلاسل النصية إحدى الأشكال الشائعة من البيانات في عالم البرمجة، وقد نحتاج إلى تحويل السلاسل النصية إلى أعداد أو أعداد إلى سلاسل نصية في كثير من الأحيان خاصةً عندما نعمل على البيانات التي ينشئها المستخدِمون.
</p>

<h3>
	تحويل الأعداد إلى سلاسل نصية
</h3>

<p>
	يمكن إنجاز ذلك من خلال استخدام التابع <code>strconv.Itoa</code> من إحدى حزم لغة جو القياسية <code>strconv</code> في حزمة جو القياسية. وذلك بتمرير العدد الصحيح أو العشري إلى هذا التابع والذي سيتكفل بإجراء عملية التحويل إلى سلسلة نصية، إذ سنحوّل العدد الصحيح 12 إلى سلسلة نصية في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_90" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strconv"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    a </span><span class="pun">:=</span><span class="pln"> strconv</span><span class="pun">.</span><span class="typ">Itoa</span><span class="pun">(</span><span class="lit">12</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q\n"</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عرّفنا متغير <code>a</code> يُمثّل سلسلة نصية وأسندنا إليه القيمة المُعادة من الدالة <code>strconv.Itoa</code> والتي ستعبّر عن العدد 12 بوصفه سلسلةً نصيةً، ثم استخدمنا دالة الطباعة لإظهار نتيجة التحويل، كما أننا استخدمنا معها العنصر النائب <code>q%</code> لإظهار السلسلة النصية مع علامتي الاقتباس ويكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_92" style=""><span class="str">"12"</span></pre>

<p>
	تشير علامات الاقتباس حول العدد 12 إلى أنّ العدد الصحيح قد أصبح سلسلةً نصيةً.
</p>

<p>
	يمكنك البدء في معرفة مدى إمكانية تحويل الأعداد الصحيحة إلى سلاسل من خلال المتغيرات، ولنفترض أنك تريد تتبع التقدم اليومي في <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">البرمجة</a> للمستخدِم وتريد إدخال عدد سطور التعليمات البرمجية التي يكتبها في كل مرة، كما تريد عرض هذه الملاحظات للمستخدِم مع طباعة قيم السلسلة والأعداد الصحيحة في الوقت نفسه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_94" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    user </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">
    lines </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">50</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Congratulations, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> user </span><span class="pun">+</span><span class="pln"> </span><span class="str">"! You just wrote "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lines </span><span class="pun">+</span><span class="pln"> </span><span class="str">" lines of code."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيعطي الخرج الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_96" style=""><span class="pln">invalid operation</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Congratulations, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> user </span><span class="pun">+</span><span class="pln"> </span><span class="str">"! You just wrote "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln">lines </span><span class="pun">(</span><span class="pln">mismatched types 
string and </span><span class="typ">int</span><span class="pun">)</span></pre>

<p>
	لا يمكنك وصل السلاسل النصية مع الأعداد الصحيحة في جو، لذلك يجب عليك تحويل المتغير <code>lines</code> إلى سلسلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_99" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strconv"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    user </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">
    lines </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">50</span><span class="pln">
            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Congratulations, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> user </span><span class="pun">+</span><span class="pln"> </span><span class="str">"! You just wrote "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> strconv</span><span class="pun">.</span><span class="typ">Itoa</span><span class="pun">(</span><span class="pln">lines</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"</span><span class="pln"> lines of code</span><span class="pun">.”)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_101" style=""><span class="typ">Congratulations</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pun">!</span><span class="pln"> </span><span class="typ">You</span><span class="pln"> just wrote </span><span class="lit">50</span><span class="pln"> lines of code</span><span class="pun">.</span></pre>

<p>
	إذا أردت تحويل عدد عشري إلى سلسلة، فالأمر مشابه لما سبق. استخدم التابع <code>fmt.Sprint</code> من الحزمة <code>fmt</code> من <a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%88%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%88%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%84%D9%83-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r241/" rel="">مكتبة</a> جو القياسية، إذ يعيد هذا التابع السلسلة النصية المكافئة للعدد العشري الذي مررته له:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_70" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Sprint</span><span class="pun">(</span><span class="lit">421.034</span><span class="pun">))</span><span class="pln">

    f </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5524.53</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Sprint</span><span class="pun">(</span><span class="pln">f</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_104" style=""><span class="lit">421.034</span><span class="pln">
</span><span class="lit">5524.53</span></pre>

<p>
	يمكنك إجراء تجربة وصل عدد حقيقي مع سلسلة نصية بعد تحويله إلى سلسلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_68" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    f </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5524.53</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy has "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprint</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">" points."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_66" style=""><span class="typ">Sammy</span><span class="pln"> has </span><span class="lit">5524.53</span><span class="pln"> points</span><span class="pun">.</span></pre>

<p>
	نجحت عملية التحويل بالفعل والدليل على ذلك أن عملية الوصل نجحت.
</p>

<h2>
	تحويل السلاسل إلى أعداد
</h2>

<p>
	يمكن استخدام الحزمة <code>strconv</code> من مكتبة جو القياسية لإنجاز عملية التحويل من سلاسل نصية إلى أعداد صحيحة وعشرية، إذ تحتاج لهكذا عملية تحويل كثيرًا لا سيما عندما تحتاج إلى إدخال البيانات من المستخدِم، فقد تحتاج مثلًا إلى أن يُدخل المستخدِم عمره والذي تُعده جو سلسلةً وليس عددًا، لذا أنت بحاجة إلى تحويله إلى عدد صحيح، فإذا كان العدد المدخل صحيحًا، فاستخدم الدالة <code>strconv.Atoi</code>؛ أما إذا كان عشريًا، فاستخدم الدالة <code>strconv.ParseFloat</code>.
</p>

<p>
	سنكمل الآن مع المثال السابق نفسه الذي تحدثنا فيه عن المستخدِم الذي يتتبع سطور التعليمات البرمجية المكتوبة كل يوم، فإذا أردت معالجة تلك القيم رياضيًا لتقديم ملاحظات أكثر تشويقًا للمستخدِم، فستحتاج لتحويلها إلى أعداد أولًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_64" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    lines_yesterday </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"50"</span><span class="pln">
    lines_today </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"108"</span><span class="pln">

    lines_more </span><span class="pun">:=</span><span class="pln"> lines_today </span><span class="pun">-</span><span class="pln"> lines_yesterday

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">lines_more</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	سيتولد الخطأ التالي عند تنفيذ الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_109" style=""><span class="pln">invalid operation</span><span class="pun">:</span><span class="pln"> lines_today </span><span class="pun">-</span><span class="pln"> lines_yesterday </span><span class="pun">(</span><span class="kwd">operator</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> not defined on string</span><span class="pun">)</span></pre>

<p>
	المتغيران اللذان تحاول طرحهما مُمثلان على أساس سلاسل نصية، لذا لا يمكن إجراء حسابات عليهما، وبالتالي سنصلح المشكلة من خلال استخدام التابع <code>strconv.Atoi()‎</code> لتحويل قيم المتغيرات إلى أعداد صحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_111" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"log"</span><span class="pln">
    </span><span class="str">"strconv"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    lines_yesterday </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"50"</span><span class="pln">
    lines_today </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"108"</span><span class="pln">

      yesterday</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> strconv</span><span class="pun">.</span><span class="typ">Atoi</span><span class="pun">(</span><span class="pln">lines_yesterday</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    today</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> strconv</span><span class="pun">.</span><span class="typ">Atoi</span><span class="pun">(</span><span class="pln">lines_today</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> nil </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="typ">Fatal</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    lines_more </span><span class="pun">:=</span><span class="pln"> today </span><span class="pun">-</span><span class="pln"> yesterday

            fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">lines_more</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدمنا <code>if</code> لتجنب توقف البرنامج بسبب حدوث خطأ غير متوقع مثل أن تكون السلسلة التي نرغب بتحويلها ليست عددًا صحيحًا أساسًا أو أنها سلسلة فارغة، ويدلنا على حدوث مثل هذه الأخطاء الدالة <code>strconv.Atoi</code> من خلال إعادة القيمة <code>nil</code> في حال كانت السلسلة الممررة غير ملائمة لعملية التحويل، وبالتالي في حال حدوث خطأ سندخل إلى تعليمة <code>if</code> ثم سنسجّل الخطأ من خلال <code>log.Fatal</code> ونخرج من البرنامج.
</p>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_113" style=""><span class="lit">58</span></pre>

<p>
	إذا حاولت تحويل سلسلة لا تمثّل عددًا صحيحًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_115" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strconv"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    a </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"not a number"</span><span class="pln">
    b</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> strconv</span><span class="pun">.</span><span class="typ">Atoi</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فستحصل على الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_117" style=""><span class="lit">0</span><span class="pln">
strconv</span><span class="pun">.</span><span class="typ">Atoi</span><span class="pun">:</span><span class="pln"> parsing </span><span class="str">"not a number"</span><span class="pun">:</span><span class="pln"> invalid syntax</span></pre>

<p>
	لم تُسنَد قيمة إلى المتغير <code>b</code> نظرًا لفشل الدالة <code>strconv.Atoi</code> في إجراء التحويل على الرغم من أنه قد صُرِّح عن <code>b</code>، ولاحظ أنّ قيمة <code>b</code> تساوي <code>0</code>، وذلك لأنّ جو لديها قيم افتراضية يُشار إليها بالقيم الصفرية في جو، كما توفر <code>strconv.Atoi</code> خطأً يصف سبب فشل تحويل السلسلة النصية أيضًا.
</p>

<h2>
	التحويل بين السلاسل والبايتات
</h2>

<p>
	تُخزّن السلاسل النصية في جو على هيئة شريحة من البايتات، ويمكنك التحويل من سلسلة إلى شريحة من البايت أو العكس من خلال الدوال <code>()byte[]</code> و <code>()string</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_119" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    a </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"my string"</span><span class="pln">

    b </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">byte</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">

    c </span><span class="pun">:=</span><span class="pln"> string</span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln">

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	خزّنتَ هنا سلسلةً في المتغير <code>a</code> ثم حوّلتها إلى شريحة من البايتات <code>b</code> ثم حوّلتها إلى سلسلة <code>c</code> من جديد، وبعد ذلك طبعتَ <code>a</code> و <code>b</code> و <code>c</code> على الشاشة، ويكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8331_121" style=""><span class="pln">my string
</span><span class="pun">[</span><span class="lit">109</span><span class="pln"> </span><span class="lit">121</span><span class="pln"> </span><span class="lit">32</span><span class="pln"> </span><span class="lit">115</span><span class="pln"> </span><span class="lit">116</span><span class="pln"> </span><span class="lit">114</span><span class="pln"> </span><span class="lit">105</span><span class="pln"> </span><span class="lit">110</span><span class="pln"> </span><span class="lit">103</span><span class="pun">]</span><span class="pln">
my string</span></pre>

<p>
	يمثِّل السطر الأول السلسلة النصية الأصلية ويمثِّل السطر الثاني السلسلة النصية بعد تحويلها إلى شريحة من البايتات؛ أما السطر الثالث، فيُظهر أمان عملية التحويل من وإلى شريحة بايتات.
</p>

<h2>
	الخاتمة
</h2>

<p>
	وضحنا في هذا المقال كيفية تحويل العديد من أنواع البيانات الأصلية المهمة إلى أنواع بيانات أخرى باستخدام التوابع المُضمّنة، إذ يوفِّر لك تحويل أنواع البيانات في جو مرونةً إضافيةً في مشاريعك البرمجية.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-convert-data-types-in-go" rel="external nofollow">How To Convert Data Types inGo</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/" rel="">استخدام المتغيرات والثوابت في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D8%A7%D9%84%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A7%D8%AA-arrays-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-go-r840/" rel="">مقدمة عن المصفوفات Arrays والشرائح Slices الخاصة بلغة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/3-%D8%B7%D8%B1%D8%A7%D8%A6%D9%82-%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-go-r839/" rel="">3 طرائق لنسخ الملفات في Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1845</guid><pubDate>Wed, 11 Jan 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62B;&#x648;&#x627;&#x628;&#x62A; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AB%D9%88%D8%A7%D8%A8%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1844/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1111650236_-11-------Go.png.138b0dadd89081511eaf700b5f060c05.png" /></p>
<p>
	تُعَدّ المتغيرات مفهومًا برمجيًا مهمًا يتوجّب عليك فهمه وإتقانه، فهي رموز تدل على القيم التي تستخدِمها في برنامجك، وسنتحدّث في هذا المقال عن أساسيات المتغيرات وأفضل الممارسات عند التعامل معها.
</p>

<h2>
	فهم المتغيرات
</h2>

<p>
	تُخصَّص للمتغير من الناحية الفنية مساحة تخزينية في الذاكرة توضَع القيمة المرتبطة به فيها، ويُستخدَم اسم المتغير للإشارة إلى تلك القيمة المُخزَّنة في ذاكرة البرنامج والتي هي جزء من <a href="https://academy.hsoub.com/certificates/comptia/%D8%A7%D9%84%D8%B0%D8%A7%D9%83%D8%B1%D8%A9-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-r59/" rel="">ذاكرة الحاسوب</a>، ويشبه المُتغيِّر بأنه عنوان تُعلِّقه على قيمة مُعيَّنة كما في الصورة التالية، إذ تشير variable name إلى اسم المتغير وvalue إلى قيمته:
</p>

<p style="text-align: center;">
	<img alt="فهم المتغيرات" class="ipsImage ipsImage_thumbnailed" data-fileid="115944" data-ratio="50.00" data-unique="kj48sqt2o" style="width: 450px; height: auto;" width="650" src="https://academy.hsoub.com/uploads/monthly_2023_01/variable1.thumb.png.71ca92d3ed9d4d81b571b3436a3d5241.png">
</p>

<p>
	لنفترض أنه لدينا عددًا صحيحًا يساوي <code>1032049348</code> ونريد تخزينه في متغيِّر بدلًا من إعادة كتابة هذا العدد الطويل كل مرة، لذلك سنستخدِم شيئًا يُسهِّل تذكّره مثل المتغير i،
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2842_11" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">1032049348</span></pre>

<p>
	إذا نظرنا إليه على أنَّه عنوانٌ مرتبط بقيمة، فسيبدو على النحو التالي:
</p>

<p style="text-align: center;">
	<img alt="منح عدد صحيح تسمية متغير سهل لحفظه بالذاكرة" class="ipsImage ipsImage_thumbnailed" data-fileid="115945" data-ratio="50.00" data-unique="9gnfqf2nz" style="width: 450px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2023_01/variable2.thumb.png.b195f2a20eae8d356b238a0a6f5a8d00.png">
</p>

<p>
	يمثّل <code>i</code> اسم المتغير وتُربَط به القيمة <code>1032049348</code> التي هي من نوع عدد صحيح integer، كما تُعَدّ العبارة <code>i := 1032049348</code> أنها تعليمة إسناد وتتألف من الأجزاء التالية:
</p>

<ul>
	<li>
		اسم المتغير <code>i</code>.
	</li>
	<li>
		معامِل تعريف المتغير المختصر <code>=:</code>.
	</li>
	<li>
		القيمة التي أُسنِدَت إلى المتغير <code>1032049348</code>.
	</li>
</ul>

<p>
	نوع البيانات تكتشفه اللغة تلقائيًا.
</p>

<p>
	تُسند القيمة السابقة من خلال هذه الأجزاء إلى المتغير i، ونكون عند تحديد قيمة المتغير قد هيّئنا أو أنشأنا ذلك المتغير، وبعد ذلك يمكنك استخدام ذلك المتغير بدلًا من القيمة كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_15" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">1032049348</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ويكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_17" style=""><span class="lit">1032049348</span></pre>

<p>
	يسهل استخدام المتغيرات علينا إجراء العمليات الحسابية، إذ سنعتمد في المثال التالي على التعليمة السابقة <code>i = 1032049348</code> وسنطرح من المتغير <code>i</code> القيمة <code>813</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_19" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i </span><span class="pun">-</span><span class="pln"> </span><span class="lit">813</span><span class="pun">)</span></pre>

<p>
	ويكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_21" style=""><span class="lit">1032048535</span></pre>

<p>
	يُجري جو Go العملية الحسابية ويطرح 813 من المتغير <code>i</code> ويعيد القيمة <code>1032048535</code>.
</p>

<p>
	يمكن ضبط المتغيرات وجعلها تساوي ناتج عملية حسابية ما، إذ سنجمع الآن عددين معًا ونخزِّن قيمة المجموع في المتغير <code>x</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_23" style=""><span class="pln">x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">76</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">145</span></pre>

<p>
	يشبه المثال أعلاه إحدى المعادلات التي تراها في كتب الجبر، إذ تُستخدَم المحارف والرموز لتمثيل الأعداد والكميات داخل الصيغ والمعادلات، وبصورة مماثلة تُعَدّ المتغيرات أسماءً رمزيةً تمثِّل قيمةً من نوع بيانات معيّن، والفرق في <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">لغة جو</a> أنه عليك التأكد دائمًا من كتابة المتغير على الجانب الأيسر من المعادلة، ولنطبع الآن <code>x</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_25" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">76</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">145</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_27" style=""><span class="lit">221</span></pre>

<p>
	أعادت جو القيمة <code>221</code> لأنه قد أُسنِد إلى المتغير <code>x</code> مجموع العددين <code>76</code> و <code>145</code>، كما يمكن أن تمثل المتغيرات أيّ نوع بيانات وليس الأعداد الصحيحة فقط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_29" style=""><span class="pln">s </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Hello, World!"</span><span class="pln">
f </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">45.06</span><span class="pln">
b </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="com">// ستُرجع قيمة منطقية، إما صواب أو خطأ</span><span class="pln">
array </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">4</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"item_1"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"item_2"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"item_3"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"item_4"</span><span class="pun">}</span><span class="pln">
slice </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"one"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"two"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"three"</span><span class="pun">}</span><span class="pln">
m </span><span class="pun">:=</span><span class="pln"> map</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"letter"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"g"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"number"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"seven"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"symbol"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"&amp;"</span><span class="pun">}</span></pre>

<p>
	فإذا طبعت أيًّا من المتغيرات المذكورة أعلاه، فستعيد جو قيمة المتغير، ففي الشيفرة التالية مثلًا سنطبع متغيرًا يمثّل شريحة slice من سلسلة نصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_31" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    slice </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"one"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"two"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"three"</span><span class="pun">}</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">slice</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_33" style=""><span class="pun">[</span><span class="pln">one two three</span><span class="pun">]</span></pre>

<p>
	لقد حددنا الشريحة <code>‎[]string{"one", "two", "three"}‎</code> إلى المتغير <code>slice</code> ثم استخدمنا دالة الطباعة <code>fmt.Println</code> لطباعتها.
</p>

<p>
	تأخذ المتغيرات مساحةً صغيرةً من ذاكرة الحاسوب لتسمح لك بوضع القيم في تلك المساحة.
</p>

<h2>
	التصريح عن المتغيرات
</h2>

<p>
	هناك عدة طرق للتصريح عن متغير في جو، فيمكن التصريح عن متغير يسمى <code>i</code> من نوع البيانات <code>int</code> بدون تهيئة، أي بدون قيمة أوليّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_36" style=""><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">int</span></pre>

<p>
	يمكن تهيئة المتغير من خلال استخدام المعامِل <code>=</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_38" style=""><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">int</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	يُطلق على كل من هذين النموذجين للتصريح بالتصريح الطويل للمتغيرات long variable declaration، في حين يمثِّل النوذج التالي الأسلوب القصير أو المختصر short variable declaration:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_40" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	في هذه الحالة نحن لانحدد <a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1726" rel="">نوع البيانات</a> ولانستخدِم الكلمة المفتاحية var، حيث يستنتج جو الصنف تلقائيًّا.
</p>

<p>
	تبنى مجتمع جو المصطلحات التالية من خلال الطرق الثلاث للتصريح عن المتغيرات:
</p>

<ul>
	<li>
		استخدِم النموذج الطويل <code>var i int</code> عندما لا تُهيئ المتغير فقط.
	</li>
	<li>
		استخدِم النموذج المختصر <code>i := 1</code>، عند التصريح والتهيئة.
	</li>
	<li>
		إذا لم تكن ترغب في أن يستنتج جو نوع البيانات الخاصة بك، ولكنك لا تزال ترغب في استخدام تصريح قصير للمتغير، فيمكنك تمرير القيمة إلى باني نوع البيانات الذي تريده كما يلي:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_42" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> int64</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	في حين لا يُعَدّ استخدام النموذج الطويل التالي من المصطلحات الشائعة في جو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_44" style=""><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">int</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	يُعَدّ اتباع الطريقة التي يحدد فيها مجتمع جو عادات التصريح عن المتغيرات من الممارسات الجيدة، وذلك حتى يتمكن الآخرون من قراءة برامجك بسلاسة.
</p>

<h2>
	القيم الصفرية Zero Values
</h2>

<p>
	تأخذ أنواع البيانات المُعرّفة ضمن جو قيمًا صفرية على أساس قيمة أوليّة في حال لم تحدَّد لها قيمة أولية كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_46" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> a </span><span class="kwd">int</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> b string
    </span><span class="kwd">var</span><span class="pln"> c float64
    </span><span class="kwd">var</span><span class="pln"> d bool

    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"var a %T = %+v\n"</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"var b %T = %q\n"</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"var c %T = %+v\n"</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"var d %T = %+v\n\n"</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_48" style=""><span class="kwd">var</span><span class="pln"> a </span><span class="kwd">int</span><span class="pln"> </span><span class="pun">=</span><span class="pln">  </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> b string </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> c float64 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> d bool </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span></pre>

<p>
	يُستخدم الرمز <code>T%</code> داخل الدالة <code>fmt.Printf</code> لطباعة نوع بيانات المتغير. لاحظ أن القيمة الصفرية المقابلة للسلاسل النصية تمثّلها السلسلة "" والقيمة الصفرية للبيانات المنطقية <code>bool</code> تمثّلها القيمة <code>false</code>. هذا مهم ففي بعض اللغات توضع قيم عشوائية للمتغيرات في حال لم تُهيئ بقيمة أولية، وبالتالي قد نرى أن متغيرًا منطقيًا يأخذ القيمة None أو شيء آخر، وهذا يُنتج عدم اتساقية للبيانات، فالصنف bool لا يمكن أن يكون إلا False أو True.
</p>

<h2>
	قواعد تسمية المتغيرات
</h2>

<p>
	تتميز تسمية المتغيرات بمرونة عالية، ولكن هناك بعض القواعد التي عليك أخذها في الحسبان كما يلي:
</p>

<ul>
	<li>
		يجب أن تكون أسماء المتغيرات من كلمة واحدة فقط بدون مسافات.
	</li>
	<li>
		يجب أن تتكوّن أسماء المتغيرات من المحارف والأعداد والشرطة السفلية <code>_</code> فقط.
	</li>
	<li>
		لا ينبغي أن تبدأ أسماء المتغيرات بعدد.
	</li>
</ul>

<p>
	دعنا نلقي نظرةً على بعض الأمثلة باتباع القواعد المذكورة أعلاه:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				صالح
			</th>
			<th>
				غير صالح
			</th>
			<th>
				التفسير
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				user-Name
			</td>
			<td>
				userName
			</td>
			<td>
				غير مسموح استخدام الواصلات Hyphens
			</td>
		</tr>
		<tr>
			<td>
				4i
			</td>
			<td>
				i4
			</td>
			<td>
				لا يمكن البدء برقم
			</td>
		</tr>
		<tr>
			<td>
				user
			</td>
			<td>
				user$
			</td>
			<td>
				لا يمكن استخدام أيّ رمز غير الشرطة السفلية
			</td>
		</tr>
		<tr>
			<td>
				user Name
			</td>
			<td>
				userName
			</td>
			<td>
				لا ينبغي للمتغير أن يتكون من أكثر من كلمة واحدة
			</td>
		</tr>
	</tbody>
</table>

<p>
	من الأمور التي يجب أخذها في الحسبان عند تسمية المتغيرات هو أنَّها حساسة لحالة المحارف، وهذا يعني أنَّ <code>my_int</code> و <code>MY_INT</code> و <code>My_Int</code> و <code>mY_iNt</code> كلها مختلفة، أي ينبغي أن تتجنب استخدام أسماء متغيرات متماثلة لضمان ألا يحدث خلط عندك أو عند المتعاونين معك حاليًا أو في المستقبل، كما أنّ حالة المحرف الأول من المتغير لها معنى خاص في جو، فإذا بدأ المتغير بمحرف كبير، فيمكن الوصول إلى هذا المتغير من خارج الحزمة التي أُعلن عنه فيها؛ أما إذا بدأ المتغير بمحرف صغير، فهو متاح فقط داخل الحزمة التي أُعلن عنه فيها كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_50" style=""><span class="kwd">var</span><span class="pln"> </span><span class="typ">Email</span><span class="pln"> string
</span><span class="kwd">var</span><span class="pln"> password string</span></pre>

<p>
	يبدأ هنا اسم المتغير <code>Email</code> بمحرف كبير، وبالتالي يمكن الوصول إليه بواسطة حزم أخرى، في حين يبدأ المتغير <code>password</code> بمحرف صغير ولا يمكن الوصول إليه إلا داخل الحزمة الُمعلن عنه فيها.
</p>

<p>
	من الشائع في جو استخدام أسماء متغيرات مختَصرة جدًا أو قصيرة، إذ يُفضّل كتابة <code>user</code> بدلًا من كتابة <code>userName</code>، كما يلعب النطاق Scope دورًا في اختصار اسم المتغير، فكلما كان نطاق المتغير أصغر، كلما كان اسم المتغير أصغر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_52" style=""><span class="pln">names </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"Mary"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"John"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Bob"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Anna"</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> n </span><span class="pun">:=</span><span class="pln"> range names </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"index: %d = %q\n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عند استخدام المتغيرات نفسها في أماكن مختلفة من البرنامج، يُفضّل إعطاءها أسماء واضحة لكي لا يربك ذلك الأشخاص الآخرين الذين يقرأون شيفرة البرنامج، لكن في المثال أعلاه استخدمنا المتغيرين <code>i</code> و <code>n</code> لأننا نستخدِمهما مرةً واحدةً فقط ومباشرةً، لذا لن يسبب ذلك أيّ مشكلة في قراءة أو فهم الشيفرة.
</p>

<p>
	يُفضّل عند تسمية المتغيرات استخدام تنسيق سنام الجَمل camelCase أو سنام الجمل المرتفع CamelCase عند كتابة المتغيرات بدلًا من استعمال الشرطة السفلية multi_word أو العادية multi-word. الجدول التالي يتضمن بعض الملاحظات المفيدة:
</p>

<table>
	<thead>
		<tr>
			<th>
				شائع
			</th>
			<th>
				غير شائع
			</th>
			<th>
				التفسير
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				user_name
			</td>
			<td>
				userName
			</td>
			<td>
				الشرطات السفلية غير شائعة الاستخدام
			</td>
		</tr>
		<tr>
			<td>
				index
			</td>
			<td>
				i
			</td>
			<td>
				لا يُفضّل استخدام الاسم الكامل وإنما الاسم المختَصر
			</td>
		</tr>
		<tr>
			<td>
				serveHttp
			</td>
			<td>
				serveHTTP
			</td>
			<td>
				يجب كتابة الاختصارات بمحارف كبيرة
			</td>
		</tr>
	</tbody>
</table>

<p>
	الخيار الأهم الذي عليك التمسك به هو الاتساق، فإذا بدأت العمل في مشروع يستخدِم تنسيق سنام الجَمل في تسمية المتغيرات، فمن الأفضل الاستمرار في استخدام ذلك التنسيق.
</p>

<h2>
	إعادة إسناد قيم للمتغيرات Reassigning
</h2>

<p>
	يمكن تغيير قيم المتغيرات في جو بسهولة كما تشير كلمة "متغير"، وهذا يعني أنه يمكنك إسناد قيمة مختلفة إلى متغير قد أُسنِدَت له قيمة مسبقًا بسهولة بالغة، إذ تُعَدّ القدرة على إعادة الإسناد مفيدةً للغاية، فقد تحتاج مثلًا خلال أطوار برنامجك إلى استلام قيم جديدة من المستخدِم وإسنادها إلى متغير قد حُدّدَت قيمته سابقًا أو قد تحتاج إلى تغيير قيمة متغير اعتمادًا على أحداث معينة، كما أنّ سهولة إعادة إسناد قيم المتغيرات مفيدة أيضًا في البرامج الكبيرة التي قد تحتاج خلالها إلى تغيير القيم باستمرار.
</p>

<p>
	سنُسّند إلى المتغير <code>i</code> الذي نوعه <code>int</code> العدد <code>76</code> ثم نعيد إسناده بالقيمة <code>42</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_54" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">76</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">

    i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_58" style=""><span class="lit">76</span><span class="pln">
</span><span class="lit">42</span></pre>

<p>
	يوضِّح المثال أنه يمكننا تعريف متغير وإسناد قيمة له ثم تغيير قيمته بإعادة إسناد قيمة أخرى له ما بسهولة من خلال استخدام معامل الإسناد =.
</p>

<p>
	<strong>ملاحظة</strong>: لاحظ أننا نستخدِم المعامِل <code>=:</code> عند التهيئة والتصريح عن متغير والمعامِل <code>=</code> عند إعادة الإسناد (تعديل قيمة المتغير)، وبالتالي لايمكنك استخدام المعامل <code>=:</code> بدلًا من <code>=</code> عند تغيير قيمة المتغير.
</p>

<p>
	بما أنّ لغة جو هي لغة تحتاج إلى تحديد النوع typed language، فعند إسناد قيمة جديدة إلى متغير يجب أن تكون هذه القيمة من نوع بيانات المتغير، فلا يمكن مثلًا إسناد قيمة تُمثّل عددًا صحيحًا إلى متغير من نوع سلسلة نصيّة أو العكس، فإذا حاولت فعل ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_60" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">72</span><span class="pln">
i </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span></pre>

<p>
	فستحصل على الخرج التالي الذي يُمثّل خطأً، والذي يخبرك فيه بأن مثل هذه العملية غير مسموحة كما أوضحنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_62" style=""><span class="pln">cannot use </span><span class="str">"Sammy"</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type string</span><span class="pun">)</span><span class="pln"> as type </span><span class="kwd">int</span><span class="pln"> in assignment</span></pre>

<p>
	لا يمكنك أيضًا تعريف أكثر من متغير واحد بالاسم نفسه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_64" style=""><span class="kwd">var</span><span class="pln"> s string
</span><span class="kwd">var</span><span class="pln"> s string</span></pre>

<p>
	ستحصل على خطأ كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_67" style=""><span class="pln">s redeclared in </span><span class="kwd">this</span><span class="pln"> block</span></pre>

<p>
	لايمكنك استخدام المعامل <code>=:</code> بدلًا من <code>=</code> عند محاولة تعديل قيمة متغير كما أشرنا سابقًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_69" style=""><span class="pln">i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">10</span></pre>

<p>
	فالخرج التالي يُظهر خطًأ مفاده أنه لا يوجد متغير جديد على الطرف الأيسر، إذ تُفسِّر جو وجود المعامِل <code>=:</code> بأننا نريد التصريح عن متغير جديد أو تهيئته بقيمة أولية.
</p>

<pre class="ipsCode">no new variables on left side of :=
</pre>

<p>
	ستحسِّن تسمية المتغيرات الخاصة بك بطريقة سليمة قابلية قراءة برنامجك سواءً لك أو للآخرين ولاسيما عند العودة إليه مستقبلًا.
</p>

<h2>
	الإسناد المتعدد
</h2>

<p>
	يمكنك في لغة جو إسناد عدة قيم إلى عدة متغيرات في الوقت نفسه، إذ يتيح لك هذا تهيئة عدة متغيرات دفعةً واحدةً، ويمكن أن تكون كل من هذه المتغيرات من أنواع بيانات مختلفة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_71" style=""><span class="pln">j</span><span class="pun">,</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> l </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"shark"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2.05</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">j</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">k</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">l</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_73" style=""><span class="pln">shark
</span><span class="lit">2.05</span><span class="pln">
</span><span class="lit">15</span></pre>

<p>
	هنا أُسند إلى المتغير <code>j</code> السلسلة <code>"shark"</code> والمتغير <code>k</code> القيمة <code>2.05</code> والمتغير <code>l</code> القيمة <code>15</code>.
</p>

<p>
	إسناد قيم لعدة متغيرات في سطر واحد يمكن أن يجعل الشيفرة مختصَرةً ويقلل من عدد الأسطر، ولكن تأكد من أنّ ذلك ليس على حساب قابلية القراءة.
</p>

<h2>
	المتغيرات العامة والمحلية
</h2>

<p>
	عند استخدام المتغيرات داخل البرنامج، من المهم أن تضع نطاق المتغير variable scope في حساباتك، إذ يشير نطاق المتغير إلى المواضع التي يمكن الوصول منها إلى المتغير داخل الشيفرة، حيث لا يمكن الوصول إلى جميع المتغيرات من جميع أجزاء البرنامج، فبعض المتغيرات عامة وبعضها محلي، إذ تُعرّف المتغيرات العامة خارج الدوال؛ أما المتغيرات المحلية، فتوجد داخل الدوال، ويعطي المثال التالي فكرةً عن المتغيرات العامة والمحلية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_75" style=""><span class="pln">package main
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">


</span><span class="kwd">var</span><span class="pln"> g </span><span class="pun">=</span><span class="pln"> </span><span class="str">"global"</span><span class="pln">

func printLocal</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    l </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"local"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">l</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    printLocal</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">g</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_77" style=""><span class="pln">local
global</span></pre>

<p>
	استخدمنا <code>var g = "global"‎</code> للتصريح عن متغير عام خارج الدالة ثم عرّفنا الدالة <code>printLocal()‎</code> وبداخلها المتغير المحلي <code>l</code> المسنَد إليه قيمة ثم تعليمة لطباعته. في الدالة الرئيسية نستدعي الدالة <code>printLocal()‎</code> ثم نطبع قيمة المتغير العام <code>g</code>، وبما أنّ <code>g</code> متغير عام، فيمكننا الوصول إليه من داخل الدالة <code>printLocal()‎</code> مباشرةً كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_79" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">


</span><span class="kwd">var</span><span class="pln"> g </span><span class="pun">=</span><span class="pln"> </span><span class="str">"global"</span><span class="pln">

func printLocal</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    l </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"local"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">l</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">g</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    printLocal</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">g</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_81" style=""><span class="pln">local
global
global</span></pre>

<p>
	يختلف هذا المثال عن المثال السابق في أننا نحاول الوصول إلى المتغير العام <code>g</code> مباشرةً من داخل الدالة <code>printLocal</code> وهذا مايُفسّره خرج البرنامج، حيث تطبع الدالة <code>printLocal</code> قيمة كل من <code>l</code> و <code>g</code> هذه المرة وليس فقط <code>l</code>.
</p>

<p>
	إذا حاولت الوصول إلى قيمة المتغير المحلي من خارج الدالة، فستفشل وستظهر رسالة خطأ تشير إلى ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_83" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> g </span><span class="pun">=</span><span class="pln"> </span><span class="str">"global"</span><span class="pln">

func printLocal</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    l </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"local"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">l</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">l</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_85" style=""><span class="kwd">undefined</span><span class="pun">:</span><span class="pln"> l</span></pre>

<p>
	أي أن المتغير غير مُعرّف في نطاق الدالة الرئيسية، إذ لا يمكنك الوصول إلى المتغير المحلي إلا ضمن النطاق الذي عُرّف ضمنه ونطاقه في هذا البرنامج هو الدالة <code>printLocal</code>، فلنلق الآن نظرةً على مثال آخر بحيث نستخدِم اسم المتغير نفسه لمتغير عام ومتغير محلي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_87" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> num1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">

func printNumbers</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    num1 </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
    num2 </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">7</span><span class="pln">  

    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">num2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    printNumbers</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">num1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_89" style=""><span class="lit">10</span><span class="pln">
</span><span class="lit">7</span><span class="pln">
</span><span class="lit">5</span></pre>

<p>
	صرّحنا في البرنامج السابق عن المتغير <code>num1</code> مرتين؛ مرة ضمن النطاق العام <code>var num1 = 5</code> والأخرى <code>num1 := 10</code> ضمن نطاق محلي داخل الدالة <code>printNumbers</code>.
</p>

<p>
	عندما نطبع <code>num1</code> من البرنامج الرئيسي -أي داخل الدالة <code>main</code>-، سنرى قيمة 5 مطبوعةً لأن <code>main</code> لا ترى سوى المتغير العام؛ أما عندما نطبع <code>num1</code> من داخل الدالة <code>printNumbers</code>، فإنه سيرى المتغير المحلي وسوف يطبع القيمة <code>10</code>، وعلى الرغم من أنّ <code>printNumbers</code> يُنشئ متغيرًا جديدًا <code>num1</code> ويُسند له قيمة <code>10</code>، إلا أنه لا يؤثر على المتغير العام وستبقى قيمته 5.
</p>

<p>
	عند التعامل مع المتغيرات، من المهم أن تختار بين استخدام المتغيرات العامة أو المحلية. يُفضل في العادة استخدام المتغيرات المحلية، ولكن إذا وجدت نفسك تستخدم نفس المتغير في عدة دوال، فقد ترغب في جعله عامًا. أما إن كنت تحتاج المتغير داخل دالة أو صنف واحد فقط، فقد يكون الأولى استخدام متغير محلي.
</p>

<h2>
	الثوابت
</h2>

<p>
	تشبه الثوابت المتغيرات إلا أنه لا يمكن تعديلها بعد التصريح عنها، وهي مفيدة عندما تريد استخدام قيمة محددة في برنامجك ولا تريد تعديلها أبدًا مثل قيمة باي pi في الرياضيات 3.14 أو إذا أردنا التصريح عن معدل الضريبة لنظام عربة التسوق، فيمكننا استخدام ثابت ثم حساب الضريبة في مناطق مختلفة من برنامجنا، فإذا تغير معدل الضريبة في وقت لاحق، فسيتعيّن علينا فقط تغيير هذه القيمة في مكان واحد في برنامجنا؛ أما إذا استخدمنا متغيرًا، فمن الممكن تغيير القيمة عن طريق الخطأ في مكان ما في برنامجنا، مما قد يؤدي إلى حساب غير صحيح.
</p>

<p>
	يمكننا استخدام الصيغة التالية للتصريح عن ثابت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_91" style=""><span class="kwd">const</span><span class="pln"> shark </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">shark</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_93" style=""><span class="typ">Sammy</span></pre>

<p>
	إذا حاولت تعديل قيمة الثابت بعد التصريح عنه، فسنحصل على الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_95" style=""><span class="pln">cannot assign to shark</span></pre>

<p>
	يمكن أن تكون الثوابت من دون نوع <code>untyped</code>، وهذا مفيد عند التعامل مع أعداد مثل بيانات الأعداد الصحيحة، فإذا كان الثابت من النوع <code>untyped</code> فيُحوّل صراحةً، حيث لا تُحوَّل الثوابت التي لديها نوع <code>typed</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_97" style=""><span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    year     </span><span class="pun">=</span><span class="pln"> </span><span class="lit">365</span><span class="pln">
    leapYear </span><span class="pun">=</span><span class="pln"> int32</span><span class="pun">(</span><span class="lit">366</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    hours </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">24</span><span class="pln">
    minutes </span><span class="pun">:=</span><span class="pln"> int32</span><span class="pun">(</span><span class="lit">60</span><span class="pun">)</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">hours </span><span class="pun">*</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">    
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">minutes </span><span class="pun">*</span><span class="pln"> year</span><span class="pun">)</span><span class="pln">   
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">minutes </span><span class="pun">*</span><span class="pln"> leapYear</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_99" style=""><span class="lit">8760</span><span class="pln">
</span><span class="lit">21900</span><span class="pln">
</span><span class="lit">21960</span></pre>

<p>
	عرّفنا المتغير <code>year</code> على أنه ثابت من دون نوع untyped، وبالتالي يمكن استخدامه مع أيّ نوع بيانات آخر؛ أما لو حددنا له نوعًا وليكن <code>int32</code> كما فعلنا مع الثابت <code>leapYear</code>، فلن نستطيع التعامل معه إلا مع بيانات من النوع نفسه لأنه typed constant.
</p>

<p>
	عندما عرّفنا المتغير <code>hours</code> بدون تحدبد نوعه، استنتجت جو تلقائيًا أنه من النوع <code>int</code> لأننا أسندنا القيمة <code>24</code> له؛ أما عندما عرّفنا المتغير <code>minutes</code>، فقد حددنا له صراحةً نوع البيانات <code>int32</code> من خلال التعليمة <code>minutes := int32(60)‎</code>.
</p>

<p>
	دعنا الآن نتصفح كل عملية حسابية وسبب نجاحها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_101" style=""><span class="pln">hours </span><span class="pun">*</span><span class="pln"> year</span></pre>

<p>
	هنا المتغير <code>hours</code> من النوع الصحيح والثابت <code>year</code> من دون نوع، وبالتالي لإجراء العملية تحوِّل جو الثابت <code>year</code> إلى النوع المطلوب؛ أي تحوّله إلى النوع <code>int</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_103" style=""><span class="pln">minutes </span><span class="pun">*</span><span class="pln"> year</span></pre>

<p>
	هنا المتغير <code>minutes</code> من النوع <code>int32</code> والثابت <code>year</code> من دون نوع، لذا تحوِّل جو الثابت <code>year</code> إلى النوع <code>int32</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_105" style=""><span class="pln">minutes </span><span class="pun">*</span><span class="pln"> leapYear</span></pre>

<p>
	المتغير <code>minutes</code> والثابت <code>leapYear</code> كلاهما من النوع <code>int32</code>، لذا لن تحتاج جو لأيّ عملية تحويل فكلاهما متوافقان.
</p>

<p>
	إذا حاولت إجراء عملية حسابية مثل الضرب بين نوعين مختلفين أي typed، فلن ينجح الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_107" style=""><span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">hours </span><span class="pun">*</span><span class="pln"> leapYear</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2842_111" style=""><span class="pln">invalid operation</span><span class="pun">:</span><span class="pln"> hours </span><span class="pun">*</span><span class="pln"> leapYear </span><span class="pun">(</span><span class="pln">mismatched types </span><span class="kwd">int</span><span class="pln"> and int32</span><span class="pun">)</span></pre>

<p>
	هنا <code>hours</code> هي من النوع <code>int</code> كما تحدثنا والثابت <code>leapYear</code> من النوع <code>int32</code>، بما أنّ جو لغة تعتمد على تحديد النوع typed language، فهذا يعني أنّ النوعين <code>int</code> و <code>int32</code> غير متوافقين لإجراء العمليات الحسابية، ولحل المشكلة عليك تحويل أحدهما إلى نوع الآخر.
</p>

<h2>
	الخاتمة
</h2>

<p>
	لقد مررنا في هذا المقال على بعض حالات الاستخدام الشائعة للمتغيرات في جو، فالمتغيرات هي لبنة مهمة في البرمجة، إذ تُمثِّل حاضنةً لمختلف أنواع البيانات في جو ومن خلالها نستطيع إجراء العديد من العمليات وتخزين القيم التي نحتاجها.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go" rel="external nofollow">How To Use Variables and Constants in Go</a> لصاحبه Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/" rel="">التعامل مع السلاسل في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">الدليل السريع إلى لغة البرمجة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%88%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%88%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%84%D9%83-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r241/" rel="">كتابة أول برنامج (ومكتبة) لك باستخدام لغة البرمجة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-gopath-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1789/" rel="">التعرف على GOPATH في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1790/" rel="">كتابة التعليقات في لغة جو Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1844</guid><pubDate>Fri, 06 Jan 2023 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x633;&#x644;&#x627;&#x633;&#x644; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1792/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6374b621083ce_-----Go-8.png.b0337d69dcc03debcf16f72d40928f63.png" /></p>

<p>
	تُعَدّ السلسلة النصية تسلسلًا من محرف واحد -أي حرف أبجدي أو عدد أو رمز- أو أكثر ويمكن أن تكون ثابتًا constant أو متغيرًا variable، كما تتبع السلاسل النصية الترميز الموحد يونيكود Unicode (معيار يُمكّن الحواسيب من تمثيل النصوص المكتوبة بأغلب نظم الكتابة ومعالجتها، بصورة متناسقة).
</p>

<p>
	تُعَدّ السلاسل النصية في جو غير قابلة للتغيير Immutable، وهو المصطلح المعاكس لمصطلح Mutable الذي يشير إلى أنواع البيانات التي يمكن التعديل على القيم التي تحتويها حتى بعد إنشاءها. أي أنه وبعد إنشاء نوع البيانات وتخزينه في الذاكرة، يمكن التعديل على بياناته.
</p>

<p>
	تدخل النصوص في كل شيء، لذا فإن نوع البيانات الذي هو السلسلة النصية string مهم جدًا في كل <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a>، وستتعلم في هذا المقال كيفية إنشاء السلاسل وطباعتها وربطها وتكرارها وتخزينها في متغيرات.
</p>

<h2>
	صياغة السلاسل النصية String Literals
</h2>

<p>
	غالبًا ما تكون السلاسل عبارة عن نصوص عادية مكتوبة، لذا قد ترغب في العديد من الحالات أن تحصل على تحكم أكبر في كيفية ظهور هذه السلاسل بغية جعلها مقروءة أكثر للآخرين، وذلك بإضافة علامات الترقيم وفواصل الأسطر والمسافات البادئة …إلخ.
</p>

<p>
	وستتعرف فيما يلي على بعض الطرق التي يمكنك من خلالها تمثيل السلاسل النصية بالصياغة المطلوبة في جو، ولكن يجب عليك في البداية فهم الفرق بين صياغة السلسلة النصية وقيمتها؛ فالسلسلة النصية مع صياغتها هي ما نراه في الشيفرة المصدرية لبرنامج الحاسوب بما في ذلك علامتَي الاقتباس مثلًا؛ أما قيمة السلسلة، فهي ما نراه عند التعامل مع السلسلة عند تشغيل البرنامج مثل استدعاء الدالة <code>fmt.Println</code> معها، ففي برنامج طباعة النص "Hello, World!‎" مثلًا، تكون صياغة السلسلة هي "Hello, World!‎" وقيمتها هي Hello, World!‎، أي بدون علامتَي الاقتباس. إذًا قيمة السلسلة هي ما تراه خرجًا على نافذة الطرفية عند تشغيل <a href="https://academy.hsoub.com/programming/go/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A3%D9%88%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%88%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%84%D9%83-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r241/" rel="">برنامج جو</a>.
</p>

<p>
	قد تحتاج في بعض الأحيان إلى تضمين علامتَي الاقتباس بحيث تظهر في قيمة السلسلة عندما تقتبس من مصدر مثلًا، ولكن بما أنّ صياغة السلسلة وقيمتها غير متكافئين، فستحتاج غالبًا لإضافة تنسيق محدد إلى السلسلة لضمان ظهور علامة الاقتباس في قيمة السلسلة كما هو متوقع.
</p>

<h3>
	علامات الاقتباس وتفسيرها
</h3>

<p>
	تتيح <a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">لغة جو Go</a> استخدام علامات الاقتباس الخلفية ` أو علامات الاقتباس المزدوجة <code>"</code> لتعريف السلاسل النصية، فبالتالي عندما ترغب باستخدام علامات الاقتباس المزدوجة، فيمكنك تضمينها ضمن سلسلة تستخدِم علامات اقتباس خلفية والعكس بالعكس كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_11" style="">
<span class="pun">`</span><span class="typ">Sammy</span><span class="pln"> says</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello!"</span><span class="pun">`</span></pre>

<p>
	أو الحالة المعاكسة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_13" style="">
<span class="str">"Sammy likes the `fmt` package for formatting strings.."</span></pre>

<p>
	يمكنك بهذه الطريقة الجمع بين علامات الاقتباس الخلفية والمزدوجة والتحكم في عرض علامات الاقتباس داخل السلسلة النصية، لكن تذكّر أنّ استخدام علامات الاقتباس الخلفية في جو سيؤدي إلى إنشاء سلسلة نصية أولية raw string literal واستخدام علامات الاقتباس المزدوجة سيؤدي إلى إنشاء سلسلة نصية مُفسّرة interpreted string literal.
</p>

<h3>
	محارف الهروب Escape Characters
</h3>

<p>
	يمكنك استخدام محارف خاصة داخل السلاسل النصية لها معنى خاص بالنسبة <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r222/" rel="">للغة جو</a> مثل " ولكن ماذا لو أردنا استعمال علامة الاقتباس " نفسها ضمن سلسلة نصية؟ نلجأ هنا إلى مفهوم الهروب والذي يعني إخبار المُصرِّف أن لا يفسر المحرف التالي له بمعناه الخاص مثل تهريب علامة الاقتباس <code>"</code> والعكس أيضًا أي إعطاء معنى خاص مع محارف محددة إن وجدت ضمن السلسلة النصية مثل محرف السطر الجديد <code>‎\n</code>، إذ تبدأ جميع محارف الهروب بمفتاح الشرطة المائلة للخلف <code>\</code> يليها مباشرةً المحرف المراد تهريبه داخل السلسلة، ومن أبرز حالات استعمال محرف التهريب:
</p>

<ul>
<li>
		\: تهريب تفسير الشرطة المائلة \ بمعناها الخاص أي محرف التهريب نفسه.
	</li>
	<li>
		"\: تهريب علامة اقتباس مزدوجة.
	</li>
	<li>
		n\: إعطاء الحرف n معنى خاص وهو تفسيره إلى الانتقال إلى السطر التالي (أول حرف من كلمة new line أي سطر جديد) أي كأنك تضغط على حرف الإدخال enter.
	</li>
	<li>
		t\: إعطاء الحرف t معنى خاص وهو مفتاح الجدولة Tab، أي تفسيره بمسافة بادئة أفقية.
	</li>
</ul>
<p>
	سنستخدِم في المثال التالي محرف الهروب <code>"\</code> لإضافة علامات الاقتباس:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_16" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy says, \"Hello!\""</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_18" style="">
<span class="typ">Sammy</span><span class="pln"> says</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello!"</span></pre>

<p>
	إذًا باستخدام محرف الهروب <code>"\</code> يمكنك استخدام علامات الاقتباس المزدوجة لإحاطة سلسلة تتضمن نصًا بين علامتَي اقتباس مزدوجتين، وسنستخدم الآن محرف هروب آخر وهو <code>n\</code> للانتقال إلى السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_20" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"This string\nspans multiple\nlines."</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_22" style="">
<span class="typ">This</span><span class="pln"> string
spans multiple
lines</span><span class="pun">.</span></pre>

<p>
	يمكنك أيضًا استخدام عدة محارف هروب ضمن السلسلة في الوقت نفسه كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_25" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"1.\tShark\n2.\tShrimp\n10.\tSquid"</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_27" style="">
<span class="lit">1.</span><span class="pln">      </span><span class="typ">Shark</span><span class="pln">
</span><span class="lit">2.</span><span class="pln">      </span><span class="typ">Shrimp</span><span class="pln">
</span><span class="lit">10.</span><span class="pln">     </span><span class="typ">Squid</span></pre>

<p>
	يساعدك محرف الهروب <code>t\</code> في عرض البيانات المُجدولة بمحاذاة أفقية واحدة، إذ يستبدلها المُصرِّف بمسافة بادئة أفقية بطول ثابت مما يساعدك في جعل البيانات المعروضة قابلة للقراءة بوضوح.
</p>

<p>
	تُستخدَم محارف الهروب لإضافة تنسيق إضافي إلى السلاسل التي قد تكون من الصعب أو المستحيل تحقيقها، إذ لن تتمكن بدون محارف الهروب من إنشاء سلسلة مثل Sammy says, "I like to use the <code>fmt</code> package"‎.
</p>

<h3>
	السلسلة النصية الأولية raw string literal
</h3>

<p>
	لنفرض مثلًا أنك لا تريد استخدام تنسيق خاص داخل السلاسل النصية، فقد ترغب بمقارنة أو تقييم سلاسل شيفرة الحاسوب التي تستخدِم الشرطة المائلة للخلف، لذلك لا تريد أن يستخدمها جو على أساس محرف هروب، وبالتالي تخبر السلسلة النصية الأولية جو أن يتجاهل جميع التنسيقات والتفسيرات داخل سلسلة بما في ذلك محارف الهروب.
</p>

<p>
	سننشئ هنا سلسلةً أوليةً باستخدام علامتَي الاقتباس الخلفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_29" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(`</span><span class="typ">Sammy</span><span class="pln"> says</span><span class="pun">,</span><span class="pln">\"</span><span class="typ">The</span><span class="pln"> balloon\'s color is red</span><span class="pun">.</span><span class="pln">\"</span><span class="pun">`)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_31" style="">
<span class="typ">Sammy</span><span class="pln"> says</span><span class="pun">,</span><span class="pln">\"</span><span class="typ">The</span><span class="pln"> balloon\'s color is red</span><span class="pun">.</span><span class="pln">\"</span></pre>

<p>
	نستنتج أنّ استخدام سلسلة نصية أولية يؤدي إلى تجاهل علامات الاقتباس وأية محارف وتنسيقات خاصة يمكن للغة جو أن تفسرها بمعنى مختلف، وبالتالي يمكنك الاحتفاظ بالشرطة المائلة العكسية والمحارف الأخرى التي تُستخدم على أساس محارف هروب.
</p>

<h2>
	السلاسل النصية المفسرة
</h2>

<p>
	هي سلسلة نصية موضوعة بين علامتي اقتباس مزدوجتين "..". كل شيء موجود بداخل علامتي الاقتباس سيُعرض باستثناء الأسطر الجديدة (المُعبر عنها بالرمز <code>n\</code>) وعلامات الاقتباس المزدوجة. في حال أردت أن تظهر هذه الرموز أيضًا، يمكنك استخدام مفتاح الهروب (أو الإلغاء) / قبلها. مثال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_34" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Say \"hello\" to Go!"</span><span class="pun">)</span></pre>

<p>
	الخرج:
</p>

<pre class="ipsCode">
Say "hello" to Go!
</pre>

<p>
	غالبًا ستستخدم السلاسل المُفسرة لأنها تتعامل مع المحارف الخاصة وتسمح بتخطيها أيضًا (تحكم أكبر).
</p>

<h3>
	طباعة السلاسل النصية على عدة أسطر
</h3>

<p>
	تجعل طباعة السلاسل النصية على أسطر متعددة النص أكثر قابليةً للقراءة، وتمكّنك أيضًا من تجميع السلاسل لإنشاء نص مُنظّم ونظيف أو استخدامها للاحتفاظ بفواصل الأسطر في حال كانت تعبر عن قصيدة أو أغنية.
</p>

<p>
	يمكنك كتابة السلسلة بالطريقة التي تريد أن تظهر بها تمامًا وإحاطتها بعلامتَي الخلفية الاقتباس لإنشاء سلاسل تمتد على عدة أسطر، لكن لا تنسى أنّ ذلك سيجعل منها سلسلةً نصية أوليةً.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_36" style="">
<span class="pun">`</span><span class="pln">
</span><span class="typ">This</span><span class="pln"> string is on
multiple lines
within three single
quotes on either side</span><span class="pun">.</span><span class="pln">
</span><span class="pun">`</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_38" style="">
<span class="typ">This</span><span class="pln"> string is on
multiple lines
within three single
quotes on either side</span><span class="pun">.</span></pre>

<p>
	لاحظ أنّ هناك سطر بداية ونهاية فارغين، ولتجنب ذلك ضع السطر الأول فورًا بعد علامة الاقتباس الخلفي وفي السطر الأخير ضع علامة الاقتباس الخلفي مباشرةً بعد آخر كلمة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_40" style="">
<span class="pun">`</span><span class="typ">This</span><span class="pln"> string is on
multiple lines
within three single
quotes on either side</span><span class="pun">.`</span></pre>

<p>
	إذا كنت بحاجة إلى إنشاء سلسلة مفسرة متعددة الأسطر، فيمكنك إنجاز ذلك بعلامتَي اقتباس مزدوجة واستخدام العامِل <code>+</code>، ولكن ستحتاج إلى إدخال فواصل الأسطر من خلال محرف الهروب في الأماكن التي تريدها كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_42" style="">
<span class="str">"This string is on\n"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
</span><span class="str">"multiple lines\n"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
</span><span class="str">"within three single\n"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
</span><span class="str">"quotes on either side."</span></pre>

<p>
	بالرغم من أنّ علامتَي الاقتباس الخلفية تُسهّل طباعة النص الطويل وقراءته، لكن إذا كنت بحاجة إلى سلسلة نصية مفسرة، فستحتاج إلى استخدام علامتَي الاقتباس المزدوجة.
</p>

<h2>
	طباعة السلاسل
</h2>

<p>
	يمكنك طباعة السلاسل باستخدام حزمة <code>fmt</code> من مكتبة النظام ثم استدعاء الدالة <code>()Println</code> منها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_44" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Let's print out this string."</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_46" style="">
<span class="typ">Let</span><span class="str">'s print out this string.</span></pre>

<p>
	يجب عليك استيراد حزم النظام عند استخدامها، وبالتالي سيكون البرنامج اللازم لطباعة السلسلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_48" style="">
<span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Let's print out this string."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	ربط السلاسل
</h2>

<p>
	يُقصَد بربط السلاسل Concatenation ضم أو وصل السلاسل معًا من طرف إلى طرف لإنشاء سلسلة جديدة، إذ يمكنك ربط السلاسل باستخدام العامِل <code>+</code>، وضَع في الحسبان أنه عند التعامل مع الأرقام سيكون العامل <code>+</code> عاملًا للجمع، ولكن عند استخدامه مع السلاسل فهو عامل ربط.
</p>

<p>
	سنربط في المثال التالي السلسلة "Sammy" والسلسلة "Shark" لإنشاء سلسلة نصية جديدة، وسنطبع الناتج مباشرةً من خلال دالة الطباعة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_50" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"Shark"</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_52" style="">
<span class="typ">SammyShark</span></pre>

<p>
	يمكنك إضافة مسافة فارغة للفصل بين الكلمتَين من خلال إضافتها بين علامتي الاقتباس بعد الكلمة الأولى كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_54" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"Shark"</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode">
Sammy Shark
</pre>

<p>
	لا يمكنك استخدام العامل <code>+</code> بين نوعين مختلفين من البيانات، فلا يمكنك مثلًا ربط السلاسل والأعداد الصحيحة معًا، وإذا حاولت ذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_56" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Sammy"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">27</span><span class="pun">)</span></pre>

<p>
	فسيظهر الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_58" style="">
<span class="pln">cannot convert </span><span class="str">"Sammy"</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type untyped string</span><span class="pun">)</span><span class="pln"> to type </span><span class="typ">int</span><span class="pln">
invalid operation</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">27</span><span class="pln"> </span><span class="pun">(</span><span class="pln">mismatched types string and </span><span class="typ">int</span><span class="pun">)</span></pre>

<p>
	إذا أردت إنشاء السلسلة النصية "Sammy27"، فيمكنك ذلك بوضع العد <code>27</code> بين علامتَي اقتباس <code>"27"</code> بحيث لا يكون عددًا صحيحًا وإنما سلسلةًإ إذ يكون استخدام الأعداد ضمن السلاسل مفيدًا في كثير من الحالات مثل الرموز البريدية أو أرقام الهواتف، فقد ترغب مثلًا بجعل رمز البلد ورمز المنطقة معًا بدون فاصل بينهما.
</p>

<p>
	عندما تربط سلسلتين فهذا يعني أنك ستُنشئ سلسلةً جديدةً يمكنك استخدامها في جميع أنحاء برنامجك.
</p>

<h2>
	تخزين السلاسل في المتغيرات
</h2>

<p>
	المتغيرات هي مفهوم برمجي هام يشير إلى القيم ونوع القيم التي تستخدمها في برنامجك. يحدد نوع المتغير (<a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1726/" rel="">نوع البيانات</a>) نوع القيم التي يمكنه تخزينها والعمليات التي يمكن إجراؤها عليه، إذ يمكنك التفكير فيها على أساس صندوق فارغ يمكنك ملؤه بقيمة أو ببيانات، كما تُعَدّ السلاسل النصية بيانات، لذا يمكنك استخدامها لملء متغير، كما يسهِّل استخدام المتغيرات لتخزين السلاسل العمل مع السلاسل في أي برنامج.
</p>

<p>
	لتخزين سلسلة داخل متغير، ما عليك سوى إسناد السلسلة إلى متغير من النوع <code>string</code>، وسنخزّن هنا مثلًا سلسلةً داخل المتغير الذي اسميناه <code>s</code>، كما يمكنك استخدام أيّ اسم تراه مُعبّرًا، لكن يُفضل الأسماء القصيرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_60" style="">
<span class="pln">s </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy likes declaring strings."</span></pre>

<p>
	يمكنك الآن طباعة هذا المتغير الذي يُمثّل السلسلة السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_62" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_64" style="">
<span class="typ">Sammy</span><span class="pln"> likes declaring strings</span><span class="pun">.</span></pre>

<p>
	يُسهّل عليك استخدام المتغيرات مع السلاسل معالجة السلاسل والتعامل معها كثيرًا، فكل ما عليك فعله هو تخزينها في متغير مرةً واحدة لتتمكن من استخدام هذا المتغير الذي يحملها في أيّ مكان في برنامجك.
</p>

<h2>
	التعامل مع السلاسل النصية ومعالجتها
</h2>

<p>
	تحتوي حزمة <code>strings</code> في جو على العديد من الدوال المتاحة للعمل مع نوع بيانات السلسلة النصية <code>string</code>، إذ تمكّنك هذه الدوال من تعديل السلاسل والتعامل معها بسهولة، إذ تُعَدّ هذه الدوال إجراءات تتمثل بمجموعة من التعليمات البرمجية التي تُطبق على السلاسل لأهداف مختلفة. حزمة السلاسل في جو هي حزمة مدمجة (مُضمنة في الشيفرة المصدر) وبالتالي عند تثبيت جو تُثبّت معها، وبما أنها حزمة مُدمجة فهذا يعني أن كل الدوال التابعة لها مدمجة أيضًا ومتاحة للعمل مباشرةً، وستتعرف فيما يلي هذه الدوال وستتعلم كيفية استخدامها.
</p>

<h3>
	تبديل حالة الأحرف من صغير إلى كبير والعكس
</h3>

<p>
	تُستخدَم الدالتان <code>strings.ToUpper</code> و <code>strings.ToLower</code> للتبديل بين حالتَي الأحرف الكبيرة والصغيرة، حيث تحوّل الدالة الأولى كل محارف السلسلة الأولى المُعطاة إلى الحالة الكبيرة وتعيدها على أساس سلسلة جديدة وبالطبع إذا كان الحرف كبير أصلًا، فلن يتغير، في حين تحوّل الدالة الثانية المحارف إلى الحالة الصغيرة وتعيدها على أساس سلسلة جديدة.
</p>

<p>
	سنحوّل في المثال التالي كل محارف السلسلة "Sammy Shark" إلى حالتها الكبيرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_66" style="">
<span class="pln">ss </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy Shark"</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">ToUpper</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_68" style="">
<span class="pln">SAMMY SHARK</span></pre>

<p>
	يمكنك أيضًا تحويلها إلى الحالة الصغيرة:
</p>

<pre class="ipsCode">
fmt.Println(strings.ToLower(ss))
</pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_70" style="">
<span class="pln">sammy shark</span></pre>

<p>
	بما أنك تستخدم دوال السلاسل، فلابد أن ستستورد الحزمة أولًا، وإلا فلن يتعرّف المُصرِّف على تلك الدوال:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_73" style="">
<span class="pln">package main

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    ss </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy Shark"</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">ToUpper</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">))</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">ToLower</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تفيد الدالتان <code>strings.ToUpper</code> و <code>strings.ToLower</code> كثيرًا في حالة مقارنة وتقييم السلاسل، لأنه يجعل حالة المحارف بحالة متسقة، فإذا قارنت مثلًا بين كلمتَي Sammy و sammy، فستكون النتيجة أنهما غير متماثلتان لأن جو حساسة لحالة الأحرف سواءً كان ذلك بالنسبة للقيم أو المتغيرات، لكن إذا طبقت الدالة <code>strings.ToLower</code> على الكلمة الأولى قبل المقارنة، فسيكون الناتج أنهما متماثلتان، ومن هنا تأتي أهميتهما.
</p>

<h3>
	دوال البحث في السلاسل
</h3>

<p>
	تحتوي حزمة السلاسل النصية في جو على العديد من الدوال التي تمكّنك من إنجاز عمليات البحث في السلاسل مثل البحث عن تسلسل محدد من المحارف داخل سلسلة ما، ومن أشهر هذه الدوال:
</p>

<ul>
<li>
		<code>strings.HasPrefix</code> تبحث في السلسلة من بدايتها.
	</li>
	<li>
		<code>strings.HasSuffix</code> تبحث في السلسلة من نهايتها.
	</li>
	<li>
		<code>strings.Contains</code> تبحث في أيّ مكان في السلسلة.
	</li>
	<li>
		<code>strings.Count</code> تعيد عدد المرات التي ظهرت بها السلسلة ضمن السلسلة المعطاة.
	</li>
</ul>
<p>
	تسمح لك الدالة الأولى والثانية بالبحث عن محرف أو سلسلة من المحارف المحددة في بداية أو نهاية السلسلة، أي اختبار فيما إذا كانت تنتهي أو تبدأ بمجموعة من المحارف، فلاختبار فيما إذا كانت السلسلة "Sammy Shark" تبدأ بكلمة Sammy وتنتهي بكلمة Shark مثلًا، سنكتب ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_75" style="">
<span class="pln">ss </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy Shark"</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">HasPrefix</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sammy"</span><span class="pun">))</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">HasSuffix</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Shark"</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_77" style="">
<span class="kwd">true</span><span class="pln">
</span><span class="kwd">true</span></pre>

<p>
	يمكنك استخدام الدالة <code>strings.Contains</code> مثلًا لاختبار احتوائها على السلسلة "Sh":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_79" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">Contains</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Sh"</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_81" style="">
<span class="kwd">true</span></pre>

<p>
	يمكنك أيضًا حساب عدد مرات ظهور المحرف <code>S</code> في السلسلة Sammy Shark:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_83" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">Count</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">,</span><span class="pln"> </span><span class="str">"S"</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_87" style="">
<span class="lit">2</span></pre>

<p>
	سنجرب الآن حساب عدد مرات ظهور الحرف <code>s</code> بالحالة الصغيرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_90" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">Count</span><span class="pun">(</span><span class="pln">ss</span><span class="pun">,</span><span class="pln"> </span><span class="str">"s"</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_92" style="">
<span class="lit">0</span></pre>

<p>
	<strong>ملاحظة</strong>: تذكّر ما أشرنا إليه سابقًا بخصوص حساسية جو لحالة الأحرف، فهذا سيُفسّر نتيجة الخرجَين السابقَين.
</p>

<h3>
	تحديد طول السلسلة
</h3>

<p>
	تُستخدَم الدالة <code>len</code> لحساب عدد المحارف الموجودة ضمن سلسلة نصية ما -أي طولها-، وهذه الدالة مفيدة في الكثير من الحالات مثل معرفة طول السلسلة أو قص السلاسل الأطول من طول محدد أو إذا لإجبار المستخدِم على إدخال طول محدد لكلمة المرور، وفي المثال التالي سنحسب طول سلسلة محددة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_94" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">"fmt"</span><span class="pln">
    </span><span class="str">"strings"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        openSource </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy contributes to open source."</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">openSource</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_96" style="">
<span class="lit">33</span></pre>

<p>
	في المثال أعلاه أسندنا السلسلة "Sammy contributes to open source.‎" إلى المتغير <code>openSource</code> ثم مررنا المتغير <code>openSource</code> إلى الدالة <code>len</code> لحساب طولها ووضعناها ضمن الدالة <code>fmt.Println</code> لطباعة النتيجة مباشرةً، ويجب أن تضع في ذهنك أنّ الدالة <code>len</code> ستحسب طول السلسلة مع احتساب أي شيء ضمنها مثل الرموز والأرقام والفراغات …إلخ.
</p>

<h3>
	دوال معالجة السلاسل النصية وتعديلها
</h3>

<p>
	توجد دوال إضافية للتعامل مع السلاسل مثل <code>strings.Join</code> و <code>strings.Split</code> و <code>strings.ReplaceAll</code>، إذ تستخدَم الدالة <code>strings.Join</code> لربط شريحة من السلاسل مع بعضها مع إمكانية فصلها بفاصل محدد كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_98" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">Join</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"sharks"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"crustaceans"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"plankton"</span><span class="pun">},</span><span class="pln"> </span><span class="str">","</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_102" style="">
<span class="pln">sharks</span><span class="pun">,</span><span class="pln">crustaceans</span><span class="pun">,</span><span class="pln">plankton</span></pre>

<p>
	كان الفاصل هنا هو فاصلة ","، كما يمكنك مثلًا إضافة فراغ بعد الفاصلة أيضًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_100" style="">
<span class="pln">strings</span><span class="pun">.</span><span class="typ">Join</span><span class="pun">([]</span><span class="pln">string</span><span class="pun">{</span><span class="str">"sharks"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"crustaceans"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"plankton"</span><span class="pun">},</span><span class="pln"> </span><span class="str">", "</span><span class="pun">)</span></pre>

<p>
	يمكنك استخدام الدالة <code>strings.Split</code> أيضًا لتقسيم السلاسل اعتمادًا على فاصل محدد كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_104" style="">
<span class="pln">balloon </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Sammy has a balloon."</span><span class="pln">
s </span><span class="pun">:=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">Split</span><span class="pun">(</span><span class="pln">balloon</span><span class="pun">,</span><span class="pln"> </span><span class="str">" "</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج شريحةً من السلاسل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_106" style="">
<span class="pun">[</span><span class="typ">Sammy</span><span class="pln"> has a balloon</span><span class="pun">]</span></pre>

<p>
	قد يكون من الصعب تحديد محتوى هذه الشريحة بمجرد النظر إليه باستخدام الدالة <code>strings.Println</code>، لذا يمكنك استخدام الدالة <code>fmt.Printf</code> مع الرمز <code>q%</code> لطباعة السلاسل مع علامتَي الاقتباس كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_108" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q"</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_113" style="">
<span class="pun">[</span><span class="str">"Sammy"</span><span class="pln"> </span><span class="str">"has"</span><span class="pln"> </span><span class="str">"a"</span><span class="pln"> </span><span class="str">"balloon."</span><span class="pun">]</span></pre>

<p>
	توجد دالة أخرى مشابهة للدالة السابقة هي <code>strings.Fields</code>، لكن هذه الدالة تتجاهل أيّة فراغات في السلسلة وبالتالي لا تقسم إلى الحقول الفعلية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_111" style="">
<span class="pln">data </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"  username password     email  date"</span><span class="pln">
fields </span><span class="pun">:=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">Fields</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"%q"</span><span class="pun">,</span><span class="pln"> fields</span><span class="pun">)</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_115" style="">
<span class="pun">[</span><span class="str">"username"</span><span class="pln"> </span><span class="str">"password"</span><span class="pln"> </span><span class="str">"email"</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">]</span></pre>

<p>
	تستخدَم الدالة <code>strings.ReplaceAll</code> لاستبدال محرف أو عدة محارف في السلسلة بمحرف جديد أو أكثر، إذ سنمرر لهذه الدالة السلسلة المطلوب تعديلها على أساس وسيط أول، ففي المثال التالي سنمرر المتغير <code>balloon</code> الذي يحمل القيمة Sammy has a balloon ثم سنمرر لها السلسلة المطلوب استبدالها وهي has ثم السلسة البديلة وهي had كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_117" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">strings</span><span class="pun">.</span><span class="typ">ReplaceAll</span><span class="pun">(</span><span class="pln">balloon</span><span class="pun">,</span><span class="pln"> </span><span class="str">"has"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"had"</span><span class="pun">))</span></pre>

<p>
	سيكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4639_119" style="">
<span class="typ">Sammy</span><span class="pln"> had a balloon</span><span class="pun">.</span></pre>

<p>
	سيكون لديك تحكم كبير في السلاسل من خلال الدوال السابقة.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعلمت في هذه المقالة أساسيات العمل مع نوع بيانات السلاسل النصية في جو بدءًا من إنشاء السلاسل وطباعتها وربطها وتكرارها ووصولًا إلى التعامل معها على أساس متغيرات ضمن برنامجك، كما تعلمت أيضًا عدة طرق لصياغة السلاسل النصية وتنسيقها بالإضافة إلى تقنيات مثل محارف الهروب تمكّنك من عرض السلاسل النصية في برنامجك على الشاشة كما تريد لكي يتمكن المستخدِم النهائي من قراءة كل المخرجات بسهولة ثم تعرفت أخيرًا على أشهر الدوال المستخدَمة في معالجة السلاسل النصية وتعديلها.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-working-with-strings-in-go" rel="external nofollow">An Introduction to Working with Strings in Go</a> ومقال <a href="https://www.digitalocean.com/community/tutorials/how-to-format-strings-in-go" rel="external nofollow">How To Format Strings in Go</a> ومقال <a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-the-strings-package-in-go" rel="external nofollow">An Introduction to the Strings Package in Go</a> لصاحبها Gopher Guides.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/go/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1791/" rel="">تعرف على أنواع البيانات في لغة جو Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r534/" rel="">الدليل السريع إلى لغة البرمجة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%D8%A7%D9%84%D8%AF%D8%B1%D9%88%D8%B3-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-go-r884/" rel="">الدروس المستفادة من البرمجة بلغة Go</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/go/3-%D8%B7%D8%B1%D8%A7%D8%A6%D9%82-%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-go-r839/" rel="">3 طرائق لنسخ الملفات في Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1792</guid><pubDate>Wed, 30 Nov 2022 07:09:29 +0000</pubDate></item></channel></rss>
