<?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/3/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; Go</description><language>ar</language><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#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%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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6374ac81b3269_------Go-7.png.a85498cd9dad38cfc5db075e5cdf8c5b.png" /></p>

<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>.
</p>

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

<p>
	يمكن التفكير في أنواع المتغيرات كما العالم الحقيقي، فنحن نتعامل مثلًا مع الأعداد من مجموعات عددية مختلفة مثل مجموعة الأعداد الطبيعية (0 ، 1 ، 2 ، …) والأعداد الصحيحة (… ، -1 ، 0 ، 1 ، …) و<a href="https://ar.wikipedia.org/wiki/%D8%B9%D8%AF%D8%AF_%D8%BA%D9%8A%D8%B1_%D9%83%D8%B3%D8%B1%D9%8A" rel="external nofollow">الأعداد غير الكسرية</a> مثل π.
</p>

<p>
	عند التعامل مع المسائل الرياضية قد نجمع بين الأعداد التي تنتمي إلى مجموعات عددية مختلفة لنحصل على نتيجة ما مثلًا إضافة العدد 5 إلى π:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_8" style="">
<span class="lit">5</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">π</span></pre>

<p>
	يمكننا الآن الاحتفاظ بالمعادلة كما هي لتكون إجابةً أو يمكننا تقريب العدد π إلى منزلة عشرية مناسبة ثم جمعه مع العدد 5، أي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_10" style="">
<span class="lit">5</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="lit">5</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">3.14</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8.14</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_12" style="">
<span class="pln">shark </span><span class="pun">+</span><span class="pln"> </span><span class="lit">8</span></pre>

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

<h2>
	الأعداد الصحيحة
</h2>

<p>
	كما هو الحال في الرياضيات، فإن الأعداد الصحيحة Integers في الحاسب هي أعداد موجبة أو سالبة إضافةً إلى الصفر، أي (‎… ، -1 ، 0 ، 1 ، …‎).
</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>int</code>، كما يجب أن تكتب العدد الصحيح كما هو بدون فواصل بين الأعداد كما في اللغات البرمجية الأخرى، فعادةً تُفصَل الأعداد الكبيرة بفواصل لتسهيل قرائتها، فقد يُكتب المليون مثلًا بالصورة 1,000,000 وفي لغات البرمجة هذا غير مسموح، ويمكن طباعة العدد الصحيح ببساطة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_15" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(-</span><span class="lit">459</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_17" style="">
<span class="pun">-</span><span class="lit">459</span></pre>

<p>
	أو يمكنك تعريف متغير من النوع الصحيح ليمثل هذا العدد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_19" style="">
<span class="pln">var absoluteZero </span><span class="typ">int</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">459</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">absoluteZero</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_21" style="">
<span class="pun">-</span><span class="lit">459</span></pre>

<p>
	يمكنك أيضًا إجراء العمليات الحسابية على الأعداد الصحيحة في جو، ففي الشيفرة التالية سنستخدِم معامل الإسناد <code>‎:=‎</code> لتعريف وتقييم المتغير sum:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_24" style="">
<span class="pln">sum </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">116</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">68</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sum</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_26" style="">
<span class="lit">48</span></pre>

<p>
	نلاحظ أنه قد طُرح العدد 68 من العدد 116 وخُزّن الناتج 48 في المتغيّر sum.
</p>

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

<h2>
	الأعداد العشرية
</h2>

<p>
	يُعَدّ العدد ذو الفاصلة العشرية Floating-Point عددًا عشريًا ويمكن كتابته على صورة حاصل ضرب في على النحو التالي: 10*12.5 = 2^10*1.25 = 125.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_28" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(-</span><span class="lit">459.67</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_30" style="">
<span class="pun">-</span><span class="lit">459.67</span></pre>

<p>
	يمكنك أيضًا تعريف متغير يمثّله كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_32" style="">
<span class="pln">absoluteZero </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">459.67</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">absoluteZero</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_34" style="">
<span class="pun">-</span><span class="lit">459.67</span></pre>

<p>
	يمكنك أيضًا إجراء العمليات الحسابية عليه كما فعلنا مع الأعداد الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_36" style="">
<span class="pln">var sum </span><span class="pun">=</span><span class="pln"> </span><span class="lit">564.0</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">365.24</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">sum</span><span class="pun">)</span></pre>

<p>
	والنتيجة هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_39" style="">
<span class="lit">929.24</span></pre>

<p>
	يجب أن تأخذ في الحسبان أنّ العدد 3 لا يساوي العدد 3.0، إذ يشير العدد 3 إلى عدد صحيح في حين 3.0 إلى عدد عشري.
</p>

<h2>
	حجم الأنواع العددية
</h2>

<p>
	يحتوي جو على نوعين من البيانات العددية بالإضافة إلى التمييز بين الأعداد الصحيحة والعشرية، وهما الساكنة static والديناميكية dynamic، فالنوع الأول مستقل عن المعمارية architecture-independent، أي أنّ حجم البيانات بواحدة البِتّ bit لا يتغير بغض النظر عن الجهاز الذي تعمل عليه الشيفرة.
</p>

<p>
	معظم معماريات أجهزة الحاسب في هذه الأيام هي إما 32 بِتّ أو 64 بِتّ، فإذا فرضنا مثلًا أنك تريد تطوير برنامج لحاسبك المحمول، فسترغب بجعله يعمل بنظام ويندوز حديث معماريته 64 بِتّ، لكن إذا كنت تعمل على تطوير برنامج لجهاز مثل ساعة اللياقة البدنية fitness watch، فربما ستُجبر على العمل بمعمارية 32 بِتّ.
</p>

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

<p>
	يُعَدّ النوع الثاني نوعًا خاصًا بالتنفيذ implementation-specific، إذ يمكن هنا أن يختلف حجم البِتّ بناءً على المعمارية التي بُنيَ البرنامج عليها، فإذا استخدمت النوع <code>int</code>، فسيكون حجم المتغير هو 32 بِتّ عند تصريف برنامج جو لمعمارية 32 بِتّ؛ أما إذا صُرِّف البرنامج بمعمارية 64 بِتّ، فسيكون حجم المتغير 64 بِتّ، لذا يُسمى ديناميكيًا.
</p>

<p>
	هناك أنواع لأنواع البيانات نفسها إضافةً إلى أنواع البيانات ذات الأحجام المختلفة، فالأعداد الصحيحة مثلًا لها نوعين أساسيين هما ذات إشارة signed وعديمة الإشارة unsigned، فالنوع int8 هو عدد صحيح له إشارة سالبة أو موجبة ويمكن أن يكون له قيمة من ‎-128 إلى 127. أما النوع uint8 فهو عدد صحيح عديم الإشارة أي موجب دومًا، ويمكن أن يكون له فقط قيمة موجبة من 0 إلى 255.
</p>

<p>
	يمتلك جو الأنواع التالية المستقلة عن نوع المعمارية architecture-independent للأعداد الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_41" style="">
<span class="typ">uint8</span><span class="pln">       </span><span class="kwd">unsigned</span><span class="pln">  </span><span class="lit">8</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> to </span><span class="lit">255</span><span class="pun">)</span><span class="pln">
</span><span class="typ">uint16</span><span class="pln">      </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="lit">16</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> to </span><span class="lit">65535</span><span class="pun">)</span><span class="pln">
</span><span class="typ">uint32</span><span class="pln">      </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="lit">32</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> to </span><span class="lit">4294967295</span><span class="pun">)</span><span class="pln">
</span><span class="typ">uint64</span><span class="pln">      </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="lit">64</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> to </span><span class="lit">18446744073709551615</span><span class="pun">)</span><span class="pln">
</span><span class="typ">int8</span><span class="pln">        </span><span class="kwd">signed</span><span class="pln">  </span><span class="lit">8</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(-</span><span class="lit">128</span><span class="pln"> to </span><span class="lit">127</span><span class="pun">)</span><span class="pln">
</span><span class="typ">int16</span><span class="pln">       </span><span class="kwd">signed</span><span class="pln"> </span><span class="lit">16</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(-</span><span class="lit">32768</span><span class="pln"> to </span><span class="lit">32767</span><span class="pun">)</span><span class="pln">
</span><span class="typ">int32</span><span class="pln">       </span><span class="kwd">signed</span><span class="pln"> </span><span class="lit">32</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(-</span><span class="lit">2147483648</span><span class="pln"> to </span><span class="lit">2147483647</span><span class="pun">)</span><span class="pln">
</span><span class="typ">int64</span><span class="pln">       </span><span class="kwd">signed</span><span class="pln"> </span><span class="lit">64</span><span class="pun">-</span><span class="pln">bit integers </span><span class="pun">(-</span><span class="lit">9223372036854775808</span><span class="pln"> to </span><span class="lit">9223372036854775807</span><span class="pun">)</span></pre>

<p>
	تأتي أعداد الفاصلة العشرية والأعداد المركبة أو العقدية complex numbers أيضًا بأحجام مختلفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_43" style="">
<span class="typ">float32</span><span class="pln">     IEEE</span><span class="pun">-</span><span class="lit">754</span><span class="pln"> </span><span class="lit">32</span><span class="pun">-</span><span class="pln">bit floating</span><span class="pun">-</span><span class="pln">point numbers
</span><span class="typ">float64</span><span class="pln">     IEEE</span><span class="pun">-</span><span class="lit">754</span><span class="pln"> </span><span class="lit">64</span><span class="pun">-</span><span class="pln">bit floating</span><span class="pun">-</span><span class="pln">point numbers
complex64   complex numbers with </span><span class="typ">float32</span><span class="pln"> real and imaginary parts
complex128  complex numbers with </span><span class="typ">float64</span><span class="pln"> real and imaginary parts</span></pre>

<p>
	يوجد أيضًا نوعان بديلان alias للأعداد بغية إعطائها اسمًا هادفًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_45" style="">
<span class="pln">byte        alias </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">uint8</span><span class="pln">
rune        alias </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">int32</span></pre>

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

<p>
	الاسم البديل رون rune مختلف قليلًا، فعلى عكس البايت byte و uint8 اللذان يمثلان البيانات نفسها، يمكن أن يكون الرون بايتًا واحدًا أو أربعة بايتات، أي مجالًا من 8 إلى 32 بت وهو مايحدده النوع int32، كما يُستخدم الرون لتمثيل محرف الترميز الموحد يونيكود Unicode (معيار يُمكّن الحواسيب من تمثيل النصوص المكتوبة بأغلب نُظم الكتابة ومعالجتها، بصورة متناسقة).
</p>

<p>
	يحتوي جو إضافةً إلى ذلك على الأنواع التالية الخاصة بالتنفيذ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_47" style="">
<span class="typ">uint</span><span class="pln">     </span><span class="kwd">unsigned</span><span class="pun">,</span><span class="pln"> either </span><span class="lit">32</span><span class="pln"> or </span><span class="lit">64</span><span class="pln"> bits
</span><span class="typ">int</span><span class="pln">      </span><span class="kwd">signed</span><span class="pun">,</span><span class="pln"> either </span><span class="lit">32</span><span class="pln"> or </span><span class="lit">64</span><span class="pln"> bits
uintptr  </span><span class="kwd">unsigned</span><span class="pln"> integer large enough to store the uninterpreted bits of a pointer value</span></pre>

<p>
	يُحدَّد حجم الأنواع الخاصة بالتنفيذ من خلال المعمارية التي صُرّف البرنامج من أجلها.
</p>

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

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

<p>
	تحدثنا سابقًا أنّ هناك أنواع مستقلة عن المعمارية وأنواع خاصة بالتنفيذ، فبالنسبة لبيانات الأعداد الصحيحة من الشائع في جو استخدام أنواع تنفيذ مثل <code>int</code> أو <code>uint</code> بدلًا من <code>int64</code> أو<code>uint64</code>، إذ ينتج عن ذلك عادةً سرعة معالجة أكبر على المعمارية المستهدفة، فإذا كنت تستخدم <code>int64</code> مثلًا وأنجزت عملية التصريف على معمارية 32 بِتّ، فسيستغرق الأمر ضعف الوقت على الأقل لمعالجة هذه القيم بحيث تستغرق دورات معالجة إضافية لنقل البيانات من معمارية لأخرى؛ أما إذا استخدمت <code>int</code> بدلًا من ذلك، فسيعرّفه البرنامج على أنه حجم 32 بِتّ لمعمارية 32 بِتّ وسيكون أسرع في المعالجة.
</p>

<p>
	إذا كنت تعرف أنّ بياناتك لن تتجاوز مجالًا محددًا من القيم، فإن اختيار نوع مستقل عن المعمارية يمكن أن يزيد السرعة ويقلل من استخدام الذاكرة، فإذا كنت تعلم مثلًا أنّ بياناتك لن تتجاوز القيمة 100 وستكون موجبةً فقط، فسيجعل اختيار <code>uint8</code> برنامجك أكثر كفاءةً لأنه يتطلب ذاكرةً أقل.
</p>

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

<h2>
	الفرق الطفحان والالتفاف Overflow vs Wraparound
</h2>

<p>
	تتعامل جو مع حالة الطفحان overflow أو بلوغ الحد الأعظمي wraparound عند محاولة تخزين قيمة أكبر من نوع البيانات المصمم لتخزينه اعتمادًا على ما إذا كانت القيمة محسوبة في وقت التصريف compile time أو في وقت التشغيل runtime، إذ يحدث خطأ في وقت التصريف عندما يعثر البرنامج على خطأ أثناء محاولته إنشاء البرنامج؛ أما الخطأ في وقت التشغيل، فيحدث بعد تصريف البرنامج أثناء تنفيذه بالفعل.
</p>

<p>
	ضبطنا قيمة المتغير <code>maxUint32</code> في المثال التالي إلى أعلى قيمة ممكنة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_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 maxUint32 </span><span class="typ">uint32</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4294967295</span><span class="pln"> </span><span class="com">// Max uint32 size</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">maxUint32</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_6524_51" style="">
<span class="typ">Output4294967295</span></pre>

<p>
	إذا أضفنا العدد <code>1</code> إلى المتغير <code>maxUint32</code> في وقت التشغيل، فسيحدث التفاف إلى القيمة <code>0</code>، أي سيكون الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_53" style="">
<span class="lit">0</span></pre>

<p>
	سنعدِّل الآن البرنامج ونضيف العدد <code>1</code> إلى المتغير <code>maxUint32</code> قبل وقت التصريف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_56" 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 maxUint32 </span><span class="typ">uint32</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4294967295</span><span class="pln"> </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">maxUint32</span><span class="pun">)</span><span class="pln">

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

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_58" style="">
<span class="pln">prog</span><span class="pun">.</span><span class="pln">go</span><span class="pun">:</span><span class="lit">6</span><span class="pun">:</span><span class="lit">36</span><span class="pun">:</span><span class="pln"> constant </span><span class="lit">4294967296</span><span class="pln"> overflows </span><span class="typ">uint32</span></pre>

<p>
	ومعرفة أحجام بياناتك وما تتعامل معه يساعد على تجنب أخطاء الطفحان تلك في برنامجك مستقبلًا لذا يجب الانتباه!
</p>

<p>
	ستتعرّف الآن على كيفية تخزين القيم المنطقية أو البوليانية boolean.
</p>

<h2>
	القيم المنطقية
</h2>

<p>
	يمتلك نوع البيانات المنطقية قيمتين؛ إما صح true أو خطأ false، وتعرَّف على أنها من النوع <code>bool</code> عند التصريح عنها، كما تُستخدَم القيم المنطقية لتمثيل قيم الحقيقة المرتبطة بالجبر المنطقي في الرياضيات والذي يُعلم الخوارزميات في علوم الحاسوب، كما يُعبَّر عن القيمتَين <code>true</code> و <code>false</code> في جو بمحرفين صغيرين دائمًا وهما <code>t</code> و <code>f</code> على التوالي.
</p>

<p>
	تُعطينا العديد من العمليات الحسابية إجابات يتم تُقيَّم إما بصح أو خطأ مثل:
</p>

<ul>
<li>
		أكبر من: 500 &gt; 100 إجابتها true أو 1 &gt; 5 إجابتها false.
	</li>
	<li>
		أقل من: 200 &lt; 400 true أو 4 &lt; 2 false.
	</li>
	<li>
		يساوي: 5 = 5 true أو 500 = 400 false.
	</li>
</ul>
<p>
	يمكنك تخزين قيمة منطقية في متغير بالصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_60" style="">
<span class="pln">myBool </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">8</span></pre>

<p>
	ثم يمكنك طباعتها من خلال الدالة <code>()fmt.Println</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_63" style="">
<span class="pln">fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">myBool</span><span class="pun">)</span></pre>

<p>
	بما أن العدد <code>5</code> ليس أكبر من <code>8</code>، فسنحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_65" style="">
<span class="kwd">false</span></pre>

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

<h2>
	السلاسل النصية Strings
</h2>

<p>
	تُعَدّ السلسلة النصية سلسلةً من محرف (حرف أبجدي أو عدد أو رمز) واحد أو أكثر، ويمكن أن تكون سلسلة ثابتة أو متغيرة.
</p>

<p>
	يوجد صياغتان لتعريف السلاسل النصية في جو، فإذا استخدمت علامتَي الاقتباس الخلفية <code>```</code> لتمثيل السلسلة بداخلها، فهذا يعني أنك ستُنشئ سلسلةً أوليّةً raw string literal؛ أما إذا استخدمت علامتَي الاقتباس المزدوجة <code>"</code>، فهذا يعني أنك ستُنشئ سلسلةً مُفسّرةً interpreted string literal.
</p>

<h3>
	السلسلة النصية الأولية
</h3>

<p>
	هي تسلسل من المحارف بين علامتَي اقتباس خلفية ````` وتُسمى أيضًا علامتَي التجزئة الخلفية back ticks.
</p>

<p>
	سيُعرض كل شيء داخل هاتين العلامتين كما هو، وهذا لا يشمل علامتَي الاقتباس، فهما مجرد دليل لنقطة بداية ونهاية السلسلة مثل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_68" style="">
<span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Say</span><span class="pln"> </span><span class="str">"hello"</span><span class="pln"> to </span><span class="typ">Go</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></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_70" style="">
<span class="typ">Say</span><span class="pln"> </span><span class="str">"hello"</span><span class="pln"> to </span><span class="typ">Go</span><span class="pun">!</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_72" style="">
<span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Say</span><span class="pln"> </span><span class="str">"hello"</span><span class="pln"> to </span><span class="typ">Go</span><span class="pun">!</span><span class="pln">\n</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></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_75" style="">
<span class="typ">Say</span><span class="pln"> </span><span class="str">"hello"</span><span class="pln"> to </span><span class="typ">Go</span><span class="pun">!</span><span class="pln">\n</span></pre>

<p>
	لاحظ أنّ السلسلة النصية السابقة هي سلسلة أوليّة، أي غير مُفسّرة، وبالتالي تُعرَض كما هي ولن يكون للرمز <code>n\</code> أيّ معنى خاص.
</p>

<p>
	تُستخدَم السلاسل الأولية أيضًا لإنشاء سلاسل متعددة الأسطر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_77" style="">
<span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">`</span><span class="typ">This</span><span class="pln"> string is on
multiple lines
within a single back
quote on either side</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></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_79" style="">
<span class="typ">This</span><span class="pln"> string is on
multiple lines
within a single back
quote on either side</span><span class="pun">.</span></pre>

<p>
	لاحظ هنا تأثير السلاسل الأولية؛ إذ ذكرنا سابقًا أنها تطبع السلسلة كما هي.
</p>

<h3>
	السلسلة النصية المفسرة
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_81" style="">
<span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Say \"hello\" to Go!"</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_6524_83" style="">
<span class="typ">Say</span><span class="pln"> </span><span class="str">"hello"</span><span class="pln"> to </span><span class="typ">Go</span><span class="pun">!</span></pre>

<p>
	ستستخدِم غالبًا السلاسل المُفسرة لأنها تتعامل مع المحارف الخاصة وتسمح بتخطيها أيضًا وبالتالي تملك تحكمًأ أكبر.
</p>

<h2>
	سلاسل صيغة التحويل الموحد UTF-8
</h2>

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

<p>
	يدعم جو صيغة التحويل هذه دون أي إعداد خاص أو مكتبات أو حزم، ويمكن تمثيل الأحرف الرومانية مثل الحرف A بقيمة ASCII مثل الرقم 65، لكن سيكون ترميز UTF-8 للمحارف الخاصة مثل المحرف 世 مطلوبًا، كما يستخدِم جو النوع رون لبيانات UTF-8.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_85" style="">
<span class="pln">a </span><span class="pun">:=</span><span class="pln"> </span><span class="str">"Hello, 世界"</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_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">

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">"Hello, 世界"</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> c </span><span class="pun">:=</span><span class="pln"> range 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">"%d: %s\n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> string</span><span class="pun">(</span><span class="pln">c</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">"length of 'Hello, 世界': "</span><span class="pun">,</span><span class="pln"> len</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>Hello, 世界</code> التي تحتوي على محارف UTF-8، ثم استخدمنا حلقة <code>for</code> مع الكلمة المفتاحية <code>range</code> للتكرار على محارف السلسلة، إذ تُفهرس الكلمة المفتاحية <code>range</code> عناصر السلسلة المحددة وتعيد قيمتين الأولى هي فهرس البايت والثانية هي قيمة البايت ا-لتي تمثِّل هنا محرف السلسلة- وبترتيب ورودها نفسه في السلسلة.
</p>

<p>
	تُستخدَم الدالة <code>fmt.Printf</code> كما هي العادة من أجل الطباعة على الشاشة، حيث حددنا لها التنسيق بالصورة <code>d: %s\n%</code>، إذ تشير <code>d%</code> إلى وجود عدد صحيح مكانها وهو الفهرس <code>i</code> الذي مثّل المُعطى الثاني للدالة، والرمز <code>s%</code> إلى وجود سلسلة نصية أو محرف وهو المحرف <code>c</code> المُمثّل بالمُعطى الثالث والرمز الأخير للانتقال إلى سطر جديد، ولاحظ أيضًا أننا وضعنا <code>c</code> ضمن الدالة <code>string</code> وذلك لكي تعامل معاملة سلسلة، ثم طبعنا أخيرًا طول المتغير <code>a</code> من خلال استخدام الدالة <code>len</code>.
</p>

<p>
	كما ذكرنا سابقُا؛ الرون هو اسم بديل للنوع <code>int32</code> ويمكن أن يتكون من واحد إلى أربعة بايت، إذ يُستخدم 3 بايتات لتمثيل المحرف <code>世</code> والكلمة المفتاحية <code>range</code> تُدرك ذلك، وبالتالي عندما تصل إليه تقرأ 3 بايتات متتالية على أنها فهرس لمحرف واحد وهذا واضح من الخرج التالي.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_89" style="">
<span class="lit">0</span><span class="pun">:</span><span class="pln"> H
</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> e
</span><span class="lit">2</span><span class="pun">:</span><span class="pln"> l
</span><span class="lit">3</span><span class="pun">:</span><span class="pln"> l
</span><span class="lit">4</span><span class="pun">:</span><span class="pln"> o
</span><span class="lit">5</span><span class="pun">:</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="lit">7</span><span class="pun">:</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">
length of </span><span class="str">'Hello, 世界'</span><span class="pun">:</span><span class="pln">  </span><span class="lit">13</span></pre>

<p>
	لاحظ أنه عند طباعة الطول حصلنا على 13، بينما عدد الفهارس هو 8 وهذا يُفسّر ماذكرناه في الأعلى.
</p>

<p>
	لن تعمل دائمًا مع سلاسل UTF-8، ولكن عندما تعمل معها ستكون مُدركًا لسبب تمثيلها باستخدام النوع رون الذي يمكن أن يكون طوله من 8 إلى 32 بت وليس <code>int32</code> واحدة فقط.
</p>

<h2>
	التصريح عن أنواع البيانات للمتغيرات
</h2>

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

<p>
	يمكننا تحديد متغير باستخدام الكلمة المفتاحية <code>var</code> متبوعة باسم المتغير ونوع البيانات المطلوب، إذ سنصرّح في المثال التالي عن متغير يسمى <code>pi</code> من النوع <code>float64</code>، أي الكلمة المفتاحية <code>var</code> هي أول ما يُكتب عند التصريح عن متغير، ثم اسم المتغير ثم نوع البيانات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_91" style="">
<span class="pln">var pi </span><span class="typ">float64</span></pre>

<p>
	يمكن إسناد قيمة ابتدائية للمتغير اختياريًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_94" style="">
<span class="pln">var pi </span><span class="typ">float64</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3.14</span></pre>

<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> لغةً ثابتة الأنواع statically-typed language مثل <a href="https://academy.hsoub.com/programming/c/%D8%A8%D9%86%D9%8A%D8%A9-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-c-r1607/" rel="">لغة C</a> و <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">Java</a> و <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">++C</a>، وهذا يعني أن كل تعليمة في البرنامج تُفحَص في وقت التصريف، كما يعني أيضًا أنّ نوع البيانات مرتبط بالمتغير؛ أما في اللغات ديناميكية الأنواع مثل <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a> أو <a href="https://academy.hsoub.com/programming/php/%D8%AA%D9%85%D9%87%D9%8A%D8%AF-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-php-r235/" rel="">PHP</a>، فيرتبط نوع البيانات بالقيمة، فقد يُصرَّح مثلًا عن نوع البيانات في جو عند التصريح عن المتغير كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6524_110" style="">
<span class="pln">var pi float64 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3.14</span><span class="pln">
var week int </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span></pre>

<p>
	يمكن أن يكون كل من هذه المتغيرات نوع بيانات مختلف إذا عرّفته بطريقة مختلفة، لكن بعد التصريح عنه لأول مرة لن تكون قادرًا على تغيير ذلك؛ أما في <a href="https://wiki.hsoub.com/PHP" rel="external">لغة PHP</a> فالأمر مختلف، إذ يرتبط نوع البيانات بالقيمة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_6524_108" style="">
<span class="pln">$s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"sammy"</span><span class="pun">;</span><span class="pln">         </span><span class="com">// يأخذ المتغير ديناميكًا نوع سلسلة نصية</span><span class="pln">
$s </span><span class="pun">=</span><span class="pln"> </span><span class="lit">123</span><span class="pun">;</span><span class="pln">             </span><span class="com">// يأخذ المتغير ديناميكيًا نوع عدد صحيح</span></pre>

<p>
	كان المتغير <code>s</code> سلسلةً نصيةً ثم تغيَّر إلى عدد صحيح اوتوماتيكيًا تبعًا للقيمة المُسندة إليه.
</p>

<p>
	سنتعرّف الآن على أنواع البيانات الأكثر تعقيدًا مثل المصفوفات.
</p>

<h2>
	المصفوفات Arrays
</h2>

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

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

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

<p>
	تُعرّف المصفوفات من خلال التصريح عن حجمها ثم نوع البيانات ثم القيم المحددة بين الأقواس المعقوصة <code>{}</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_112" 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_6524_114" 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>
	يمكنك إسناد المصفوفة إلى متغير ثم طباعتها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_116" style="">
<span class="pln">coral </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">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">
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 prettyprint lang-c prettyprinted" id="ips_uid_6524_118" style="">
<span class="pun">[</span><span class="pln">blue coral staghorn coral pillar coral</span><span class="pun">]</span></pre>

<h2>
	الشرائح Slices
</h2>

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

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

<p>
	يُصرّح عن الشرائح من خلال تحديد نوع البيانات مسبوقًا بقوس فتح وإغلاق مربع <code>[]</code> والقيم بين أقواس معقوصة <code>{}</code>، وفيما يلي مثالًا عن شريحة من الأعداد الصحيحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_120" 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_6524_122" 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_6524_124" 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_6524_126" 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_6524_128" 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 prettyprint lang-c prettyprinted" id="ips_uid_6524_131" style="">
<span class="pun">[</span><span class="pln">shark cuttlefish squid mantis shrimp</span><span class="pun">]</span></pre>

<p>
	يمكنك استخدام الكلمة المفتاحية <code>append</code> لإضافة عنصر جديد إلى الشريحة، وسنضيف السلسلة <code>seahorse</code> إلى الشريحة السابقة على سبيل المثال كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_133" style="">
<span class="pln">seaCreatures </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">seaCreatures</span><span class="pun">,</span><span class="pln"> </span><span class="str">"seahorse"</span><span class="pun">)</span></pre>

<p>
	سنطبع الشريحة الآن للتأكد من نجاح العملية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_135" 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 prettyprint lang-c prettyprinted" id="ips_uid_6524_137" style="">
<span class="pun">[</span><span class="pln">shark cuttlefish squid mantis shrimp seahorse</span><span class="pun">]</span></pre>

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

<h1>
	الخرائط Maps
</h1>

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

<p>
	تُنشأ الخرائط باستخدام الكلمة المفتاحية <code>map</code> متبوعة بنوع بيانات المفاتيح بين قوسين معقوفين <code>[]</code> متبوعًا بنوع بيانات القيم، ثم أزواج القيم والمفاتيح في أقواس معقوصة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_139" 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>
	عادةً ما تُستخدَم الخرائط للاحتفاظ بالبيانات المرتبطة ببعضها كما عرضنا في المثال السابق أو كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_141" 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>
	يمكنك أن تلاحظ أنه بالإضافة إلى الأقواس المعقوصة، توجد أيضًا نقطتان في جميع أنحاء الخريطة، إذ تمثل الكلمات الموجودة على يسار النقطتين المفاتيح وعلى اليمين القيم، كما تجدر الملاحظة أيضًا إلى أنّ المفاتيح يمكن أن تكون من أيّ نوع بيانات في جو، فالمفاتيح الموجودة في الخريطة (الرابطة) أعلاه هي الاسم والحيوان واللون والموقع، ويفضل أن تكون من الأنواع القابلة للمقارنة وهي الأنواع الأولية primitive types مثل السلاسل النصية <code>string</code> والأعداد الصحيحة <code>ints</code> وما إلى ذلك، إذ يُحدد النوع الأساسي من خلال اللغة ولا يُنشأ من دمج أيّ أنواع أخرى، كما يمكن للمستخدِم أيضًا تحديد أنواع جديدة، إلا أنه يُفضّل إبقاءها بسيطةً لتجنب <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>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_143" 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 prettyprint lang-c prettyprinted" id="ips_uid_6524_146" style="">
<span class="typ">map</span><span class="pun">[</span><span class="pln">animal</span><span class="pun">:</span><span class="pln">shark color</span><span class="pun">:</span><span class="pln">blue location</span><span class="pun">:</span><span class="pln">ocean name</span><span class="pun">:</span><span class="typ">Sammy</span><span class="pun">]</span></pre>

<p>
	إذا أردت الوصول إلى لون سامي sammy وطباعته فيمكنك كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_148" 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">"color"</span><span class="pun">])</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6524_151" style="">
<span class="pln">blue</span></pre>

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

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

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

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

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

<ul>
<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>
	<li>
		<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>
	</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">1791</guid><pubDate>Wed, 16 Nov 2022 09:54:52 +0000</pubDate></item><item><title>&#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x62A;&#x639;&#x644;&#x64A;&#x642;&#x627;&#x62A; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x62C;&#x648; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6374aa7fc924a_6------Go.png.61ba906ddbde9013c31c3b79d5724ee8.png" /></p>

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

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

<h2>
	صياغة التعليقات
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_7" style="">
<span class="com">// This is a comment</span><span class="pln">
</span><span class="com">// هذا تعليق على الشيفرة</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_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">"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">
    </span><span class="com">// ‫اطبع العبارة "Hello, World!‎" إلى الطرفية</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>
	مثال آخر لوضع التعليقات ضمن حلقة for التي تُكرِّر تنفيذ كتلة برمجية أو مجموعة من التعليمات البرمجية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_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="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="com">// عرف المتغير التالي على أنه شريحة من سلاسل نصية</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="com">// حلقة تكرار للمرور على كل عنصر من عناصر القائمة وطباعته</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>

<p>
	لاحظ على سبيل المثال كيف سنُعلّق على الدالة <code>main</code>، ولاحظ كيف سنضع التعليقات بما يتماشى مع كل مقطع مسبوق بمسافة بادئة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_13" 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"> favColor string </span><span class="pun">=</span><span class="pln"> </span><span class="str">"blue"</span><span class="pln">

func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var guess string
    </span><span class="com">// إنشاء حلقة تكرار</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </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="str">"Guess my favorite color:"</span><span class="pun">)</span><span class="pln">
        </span><span class="com">// اقرأ ما أدخله المستخدم واطبع النتيجة</span><span class="pln">
        </span><span class="kwd">if</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">Scanln</span><span class="pun">(&amp;</span><span class="pln">guess</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">Printf</span><span class="pun">(</span><span class="str">"%s\n"</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">
        </span><span class="com">// تأكد إن خمن اللون الصحيح</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> favColor </span><span class="pun">==</span><span class="pln"> guess </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">Printf</span><span class="pun">(</span><span class="str">"%q is my favorite color!\n"</span><span class="pun">,</span><span class="pln"> favColor</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="com">// اللون الذي أدخله خطأ ونطلب منه تكرار الإجابة</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Sorry, %q is not my favorite color. Guess again.\n"</span><span class="pun">,</span><span class="pln"> guess</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>
	يجب أن يكون التعليق على شيفرة ما هو توضيح لمضمونها أو للفكرة التي أنتجت هذه الشيفرة وليس كتابة أسئلة أو شيء آخر، أي يجب أن تُجيب التعليقات عن السبب الذي أنتج الشيفرة.
</p>

<h2>
	التعليقات الكتلية
</h2>

<p>
	يمكن استخدام التعليقات الكتليّة Block Comments -أي عدة أسطر من التعليقات- لتوضيح الشيفرات البرمجية المعقدة التي تتوقع بأن لا يكون القارئ على دراية بها، إذ تنطبق هذه التعليقات الطويلة على جزء من الشيفرة أو جميعها، كما توضع في نفس مستوى المسافة البادئة للشيفرة، كما يمكن كتابة التعليقات الكتلية بطريقتين؛ الأولى من خلال المحرفَين السابقَين <code>//</code> وتكرارهما من أجل كل سطر مثل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_15" style="">
<span class="com">// First line of a block comment</span><span class="pln">
</span><span class="com">// Second line of a block comment</span></pre>

<p>
	أما الطريقة الثانية، فمن خلال علامة الفتح <code>*/</code> التي نضعها في بداية التعليق وعلامة الإغلاق <code>*/</code> التي نضعها في نهاية التعليق، إذ يُستخدَم <code>//</code> عادةً مع عمليات التوثيق؛ أما <code>/* ... */</code> لتصحيح الأخطاء debugging.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_17" style="">
<span class="com">/*
تعليق طويل
يمتد على
أكثر من سطر
*/</span></pre>

<p>
	سنستخدم التعليقات الكتليّة في المثال التالي لتوضيح الدالة <code>()MustGet</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_19" style="">
<span class="com">// ‫تأخذ الدالة MustGet رابطًا وتعيد الصفحة الرئيسية له</span><span class="pln">
</span><span class="com">// وإن حصل أي خطأ ستظهره</span><span class="pln">
func </span><span class="typ">MustGet</span><span class="pun">(</span><span class="pln">url string</span><span class="pun">)</span><span class="pln"> string </span><span class="pun">{</span><span class="pln">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">Get</span><span class="pun">(</span><span class="pln">url</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">

    defer resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
    var body </span><span class="pun">[]</span><span class="pln">byte
    </span><span class="kwd">if</span><span class="pln"> body</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">=</span><span class="pln"> ioutil</span><span class="pun">.</span><span class="typ">ReadAll</span><span class="pun">(</span><span class="pln">resp</span><span class="pun">.</span><span class="typ">Body</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">
        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">
    </span><span class="kwd">return</span><span class="pln"> string</span><span class="pun">(</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

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

<h2>
	التعليقات السطرية
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_22" style="">
<span class="pun">[</span><span class="pln">code</span><span class="pun">]</span><span class="pln">  </span><span class="com">// تعليق سطري يشرح سطر الشيفرة</span></pre>

<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> ولم يكن هناك توضيح مسبق على سبيل المثال، فقد لا تعلم أنت أو المتعاونون معك أنّ الشيفرة التالية ستنشئ عددًا عقديًا، لذلك قد ترغب في إضافة تعليق سطري كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_25" style="">
<span class="pln">z </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">// ‫ احصل على باقي قسمة العدد x</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_27" style="">
<span class="pln">x </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">8</span><span class="pln">  </span><span class="com">// إسناد قيمة للعدد</span></pre>

<p>
	يجب استخدام التعليقات السطرية عند الضرورة وعندما توفِّر إرشادات مفيدةً للشخص الذي يقرأ البرنامج.
</p>

<h2>
	تعليق جزء من الشيفرة بدواعي الاختبار والتنقيح
</h2>

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

<p>
	يمكن أن يتيح لك استخدام الرمزين <code>/*...*/</code> تجربة بدائل أخرى أثناء إعداد الشيفرة أو للتعليق على التعليمات البرمجية التي تفشل أثناء استمرار العمل على أجزاء أخرى من التعليمات البرمجية الخاصة بك.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8824_29" style="">
<span class="com">// دالة تضيف عددين</span><span class="pln">
func addTwoNumbers</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y </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">
    sum </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> y
    </span><span class="kwd">return</span><span class="pln"> sum
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// دالة تضرب عددين</span><span class="pln">
func multiplyTwoNumbers</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y </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">
    product </span><span class="pun">:=</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> y
    </span><span class="kwd">return</span><span class="pln"> product
</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="com">/*
        ‫علقنا في هذا المقال استدعاء الدالة addTwoNumbers
        لأنه يولد خطأ لم نكتشفه فلا نريد إيقاف الشيفرة

        a := addTwoNumbers(3, 5)
        fmt.Println(a)

    */</span><span class="pln">

    m </span><span class="pun">:=</span><span class="pln"> multiplyTwoNumbers</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</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">m</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

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

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

<p>
	سيسمح لك التعليق الصحيح على الشيفرة في جو باستخدام الأداة <a href="https://godoc.org/golang.org/x/tools/cmd/godoc" rel="external nofollow">Godoc</a>، وهي أداة تستخرِج التعليقات من التعليمات البرمجية الخاصة بك وتُنشئ وثائق لبرنامج جو الخاص بك.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-write-comments-in-go" rel="external nofollow">How To Write Comments 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-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/%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%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/" rel="">بناء خادم بروتوكول التحكم في الإرسال TCP متزامن في لغة البرمجة Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1790</guid><pubDate>Sat, 24 Dec 2022 16:04:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; GOPATH &#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-gopath-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D9%88-go-r1789/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6374a52c945d3_--5-GOPATH.png.64432096f381aee3dda125dafb3bc5d8.png" /></p>

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

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

<p>
	انتبه إلى أنه بدءًا من الإصدار 1.13 أضاف مطوروا <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="">لغة Go</a> آلية جديدة لإدارة المكتبات التي يعتمد عليها مشروع مكتوب بلغة جو تدعى وحدات جو Go Modules -سنتحدث عنها لاحقًا- وأصبحت هذه الآلية الطريقة المعتمد حاليًا في إضافة إعتماديات المشروع وإدارة هيكلة مجلده الرئيسي، وصحيح أن هذه الآلية قد حلت مكان GOPATH إلا أنه من الجيد فهم الآلية القديمة هذه التي قد تكون مستعملة في مشاريع قديمة أو تمر معك في شيفرة ما، ولمزيد من التفاصيل ومعرفة أحدث المستجدات عد إلى توثيق <a href="https://go.dev/doc/tutorial/workspaces" rel="external nofollow">workspaces</a> الرسمي من <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>

<h2>
	ضبط متغير البيئة GOPATH$
</h2>

<p>
	يحمل متغير البيئة GOPATH$ قائمةً تتضمن أماكن ليبحث فيها جو عن مساحات العمل.
</p>

<p>
	يتوقع جو في الحالة الافتراضية أنّ موقع GOPATH الخاص بك هو HOME/go$، حيث HOME$ هو المجلد الجذر لحساب المستخدِم الخاص بك على الحاسب، ويمكنك تغيير ذلك من خلال تعديل متغير البيئة GOPATH$ حسب <a href="https://golang.org/doc/code.html#Workspaces" rel="external nofollow">توثيق جو</a>.
</p>

<h2>
	الفرق بين GOPATH$ و GOROOT$
</h2>

<p>
	يُعَدّ GOROOT$ المكان الذي تتواجد فيه شيفرة جو والمصرِّف compiler والأدوات الأخرى التابعة له، أي أنه لا يتضمن الشيفرة المصدرية الخاصة بك، وعادةً ما يكون مسار GOROOT$ هو usr/local/go/ ومسار GOPATH$ هو HOME/go$، كما تجدر الإشارة إلى أنك لست بحاجة إلى إعداد المتغير GOROOT$ بعد الآن، إذ كان ذلك مطلبًا في السابق.
</p>

<h2>
	مكونات مساحة العمل
</h2>

<p>
	توجد ثلاثة مجلدات داخل مساحة عمل جو أو GOPATH وهي bin و pkg و src، كما يملك كل مجلد من هذه المجلدات وظيفةً خاصةً في جو.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_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"> pkg
</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">foo</span><span class="pun">/</span><span class="pln">bar
    </span><span class="pun">└──</span><span class="pln"> bar</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	يمثّل المجلد GOPATH/bin$ المكان الذي توضع فيه الملفات الثنائية (التنفيذيّة) التي تم تثبيتها بواسطة الأمر <code>go install</code>.
</p>

<p>
	يستخدِم نظام التشغيل متغير البيئة <code>PATH$</code> للعثور على الملفات الثنائية التي يمكن تنفيذها بدون كتابة المسار الكامل، لذا يوصى بإضافة المجلد bin إلى المتغير <code>PATH$</code> العام، فإذا لم تضف GOPATH/bin$ مثلًا إلى متغير البيئة <code>PATH$</code>، فسنحتاج إلى كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_11" style="">
<span class="pln">$ $GOPATH</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">myapp</span></pre>

<p>
	أما إذا كان مُضافًا إليه لكان بالإمكان تشغيله بكتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_13" style="">
<span class="pln">$ myapp</span></pre>

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

<p>
	توضع في المجلد src شيفرة جو المصدرية وهي الملفات التي يتم كتابتها وإنشاؤها باستخدام لغة جو والتي تكون لاحقتها <code>‎.go</code>، الملفات المصدرية يستخدمها مُصرّف جو لإنشاء ملفات قابلة للتنفيذ (ملفات ثنائية يمكن تشغيلها على نظامك لتنفيذ المهام التي تتضمنها). وانتبه جيدًا مرةً أخرى إلى أنّ هذه الملفات ليست الملفات الموجودة في GOROOT$، كما ستوضع هذه الملفات في المسار GOPATH/src/path/to/code$ أثناء كتابة برامج وحزم ومكتبات جو.
</p>

<h2>
	ما هي الحزم؟
</h2>

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

<p>
	تتبع جو القواعد التالية في كيفية تقسيم برنامج إلى حزم:
</p>

<ul>
<li>
		تُخزّن الحزم مع جميع ملفات جو المصدرية المكتوبة من قبل المستخدِم ضمن المجلد GOPATH/src$.
	</li>
	<li>
		الحزمة غالبًا عبارة عن مجلد داخل مشروعك به الملفات التي تحمل اسم الحزمة.
	</li>
	<li>
		لابد من وجود حزمة واحدة على الأقل في أي برنامج أو مكتبة.
	</li>
	<li>
		إذا كان البرنامج عبارة عن برنامج تنفيذي (وليس مكتبة - library) فإنه يجب وجود حزمة باسم main (أي package main) تكون هي مدخل البرنامج كما رأينا سابقًا.
	</li>
</ul>
<p>
	وكتذكير لما ذكرناه سابقًا:
</p>

<ul>
<li>
		لابد لكل ملف شفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.
	</li>
	<li>
		لابد لكل حزمة في Go أن تنتمي إلى مجلد ما.
	</li>
	<li>
		لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات).
	</li>
	<li>
		يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.
	</li>
	<li>
		يمكن للمجلد الرئيسي لمشروعك أن يحتوي على حزمة ما، واحدة فقط، باقي الحزم الخاصة به يمكنها أن تتواجد في مجلدات فرعية.
	</li>
	<li>
		غياب حزمة main من برنامج ما، يجعل منه مكتبة فقط وليس برنامجا تشغيليا قائما بحد ذاته.
	</li>
</ul>
<p>
	إذا كانت الشيفرة الخاصة بك موجودةً في المسار GOPATH/src/blue/red$ فيجب أن يكون اسم الحزمة التي تنتمي إليها الشيفرة هو red، ويمكنك استيراد هذه الحزمة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_17" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="str">"blue/red"</span></pre>

<p>
	في حالة الحزم المتواجدة ضمن مستودعات على مواقع استضافة الشيفرات مثل GitHub و BitBucket، فيجب تضمين المسار الكامل في عملية الاستيراد، فإذا أردنا استيراد الشيفرة المصدرية من الرابط <a href="https://github.com/gobuffalo/buffalo%D8%8C" ipsnoembed="false" rel="external nofollow">https://github.com/gobuffalo/buffalo،</a> فسنكتب ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_19" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="str">"github.com/gobuffalo/buffalo"</span></pre>

<p>
	وستُخزَّن في الموقع التالي على القرص:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9928_21" 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">buffalo</span></pre>

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

<p>
	تعرّفت في هذه المقالة على المجلد GOPATH الذي يحتوي على مجموعة من المجلدات التي يتوقع جو وجود الشيفرة المصدرية الخاصة بك بداخلها، بالإضافة إلى ماهية تلك المجلدات وما تحتوي عليها، كما تعرّفت على كيفية تغيير الموقع الافتراضي HOME/go$ له، وتعرّفت على الآلية التي يبحث بها جو عن الحزم داخل بنية المجلد.
</p>

<p>
	قُدّمت Go Modules في الإصدار 1.11 من جو، وتهدف إلى استبدال مساحات عمل جو و GOPATH، وعلى الرغم من أنه يُوصى ببدء استخدامها إلا أنّ بعض البيئات قد لا تكون جاهزةً لاستخدامها مثل بيئات الشركة corporate environments.
</p>

<p>
	يُعَدّ GOPATH أكثر الجوانب تعقيدًا في إعداد جو ولكن بمجرد إعداده يمكنك نسيانه بعدها على الغالب.
</p>

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

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

<ul>
<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%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%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%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/" rel="">بناء خادم بروتوكول التحكم في الإرسال TCP متزامن في لغة البرمجة Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1789</guid><pubDate>Wed, 16 Nov 2022 09:09:07 +0000</pubDate></item><item><title>&#x643;&#x62A;&#x627;&#x628;&#x629; &#x628;&#x631;&#x646;&#x627;&#x645;&#x62C;&#x643; &#x627;&#x644;&#x623;&#x648;&#x644; &#x641;&#x64A; &#x62C;&#x648; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/63749e9fb8d17_-----4-Go.png.6bb5e0308f66fd4fb1275ca66fbff003.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>، إذ سنحاول اتباع العادة التي جرت عليها دروس تعلم <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>، وهي ببساطة كتابة جملة "Hello, World!‎" أي "أهلًا بالعالم!"، لكن سنجعل الأمور أكثر متعةً من خلال جعل البرنامج يسأل المستخدِم عن اسمه لكي يطبع الاسم بجانب عبارة الترحيب، وبعد الانتهاء من كتابة البرنامج سيكون خرج البرنامج مشابهًا للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_7" style="">
<span class="typ">Please</span><span class="pln"> enter your name</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Sammy</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'m Go!</span></pre>

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

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

<ul>
<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="">تثبيت لغة جو وإعداد بيئة برمجة محلية على أبونتو</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="http://xn--https-cdhai3fycuh/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="external nofollow">تثبيت لغة جو وإعداد بيئة برمجة محلية على ويندوز</a>.
	</li>
</ul>
<h2>
	الخطوة 1 - كتابة برنامج "Hello, World!‎" الأساسي
</h2>

<p>
	افتح محرر نصوص <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> مثل نانو nano وانشئ ملفًا جديدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_14" style="">
<span class="pln">$ nano hello</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	اكتب البرنامج التالي بعد فتح الملف النصي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_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">
  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>

<ul>
<li>
		الحزمة <code>package</code>: هي كلمة مفتاحية keyword في جو تحدِّد اسم الحزمة التي ينتمي لها هذا الملف، أي الملف الذي تكتب فيه البرنامج، إذ لا بدّ أن يكون لكل ملف حزمة ما، ولا بدّ أن تنتمي كل حزمة في جو إلى مجلد ما، كما لا يمكن لحزمتَين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات)، كما يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى. في مثالنا السابق، أعطينا <code>main</code> كاسم لحزمتنا، وهو اسم خاص، حيث يُعامل مُصرّف compiler لغة جو هذه الحزمة على أنها مدخل البرنامج، أي أن التعليمات الموجودة في هذه الحزمة يتم تشغيلها أولًا. أسبقنا اسم الحزمة بالكلمة المفتاحية <code>package</code>.
	</li>
	<li>
		<code>import</code> كلمة مفتاحية أخرى وتعني استرِد أو اجلِب المكتبة الفلانية أو الحزمة الفلانية.
	</li>
	<li>
		<code>fmt</code> اختصار format أو formatting وهي مكتبة قياسية standard library تأتي مع جو، وهي خاصة ببناء وطباعة النص. لاحظ أن اسم المكتبات أو الحزم المُراد استيرادها دائما ما يتم إحاطتها بعلامة اقتباس "".
	</li>
	<li>
		في التعبير <code>fmt.Println</code> استعملنا دالة <code>Println</code> من الحزمة <code>fmt</code> التي استوردناها، ولاستعمال أيّ حزمة في جو يكفي كتابة اسمها ثم نقطة ثم اسم الدالة التي تريد استعمالها، وهنا أردنا طباعة نص "Hello, World!‎"، لذا لاحظ أننا مررنا القيمة بين علامتَي اقتباس "" ﻷنها سلسلة نصية string.
	</li>
</ul>
<p>
	احفظ الملف البرمجي الذي أنشأته واخرج من المحرر عن طريق كتابة <code>CTRL + X</code> وتأكيد الخروج بالضغط على المفتاح Y عندما يطلب منك، ويمكنك الآن تجربة برنامجك.
</p>

<h2>
	الخطوة 2 - تشغيل البرنامج
</h2>

<p>
	يمكنك تشغيل أيّ برنامج مكتوب بلغة جو من خلال كتابة الكلمة المفتاحية <code>go</code> متبوعة باسم الملف، وبالتالي لتشغيل البرنامج السابقة سنكتب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_37" style="">
<span class="pln">$ go run hello</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_39" style="">
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!</span></pre>

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

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

<p>
	تُنفَّذ الشيفرة أو البرنامج بعد انتهاء عملية التصريف من خلال وضع الدالة <code>()main</code> في الحزمة <code>main</code>، والتي تتضمن طباعة السلسلة النصية "Hello, World!‎" عن طريق استدعاء دالة <code>fmt.Println</code> أي <code>("!fmt.Println("Hello, World</code>، وتُدعى السلسلة النصية وسيطًا لتلك الدالة بما أنها تُمرَّر إليها.
</p>

<p>
	<strong>ملاحظة</strong>: لا تُطبَع علامتَا الاقتباس الموجودتان على جانبي Hello, World!‎ على الشاشة لأنك تستخدمهما لإخبار جو من أين تبدأ السلسلة الخاصة بك وأين تنتهي.
</p>

<p>
	ستستكشف في الخطوة التالية كيفية جعل البرنامج تفاعليًّا أكثر.
</p>

<h2>
	الخطوة 3 - إدخال معلومات من المستخدم لاستخدامها في البرنامج
</h2>

<p>
	سيطبع البرنامج السابق الخرج نفسه في كل مرة تستدعيه بها، كما يمكنك إضافة بعض التعليمات إلى البرنامج بحيث تجعله يطلب من المستخدِم إدخال اسمه لكي يُطبع بجانب عبارة الترحيب.
</p>

<p>
	بإمكانك تعديل برنامجك السابق، ولكن يُفضَّل أن تُنشئ برنامجًا جديدًا يسمى greeting.go باستخدام المحرِّر نانو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_41" style="">
<span class="pln">nano greeting</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_43" 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="str">"Please enter your name."</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استخدامنا دالة <code>fmt.Println</code> لطباعة النص على الشاشة كما في المرة السابقة.
</p>

<p>
	أضف الآن السطر<code>var name string</code> لتخزين مُدخلات المستخدِم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_45" 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="str">"Please enter your name."</span><span class="pun">)</span><span class="pln">
  var name string
</span><span class="pun">}</span></pre>

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

<p>
	أضف الآن السطر <code>fmt.Scanln(&amp;name)‎</code> إلى الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_47" 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="str">"Please 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="pun">}</span></pre>

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

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

<p>
	أخيرًا، أضف السطر <code>fmt.Printf("Hi, %s! I'm Go!", name)‎</code> إلى برنامجك لطباعة الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_49" 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="str">"Please 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">
  fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Hi, %s! I'm Go!"</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>fmt.Printf</code> في عملية الطباعة ﻷنها ستسمح لنا بتنسيق عملية الطباعة بالطريقة التي نريدها، إذ تأخذ هذه الدالة وسيطَين الأول هو سلسلة نصية تتضمن العنصر النائب s% (العنصر النائب Placeholder هو متغير يأخذ قيمة في وقتٍ لاحق أي ينوب عن القيمة الحقيقة في البداية)، والثاني هو المُتغير الذي سيُحقن في هذا العنصر النائب، وهذه الدالة تُسمى دالة مرنة، أي تأخذ عددًا غير مُحدد من المعطيات، كما أن المُعطى الأول قد يتضمن أكثر من عنصر نائب لكن هذا لايهمنا الآن، ونفعل ذلك لأن لغة جو لا تدعم تضمين المتغيرات ضمن السلاسل النصية مباشرة كما تفعل لغات أخرى مثل <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1689/" rel="">لغة جافاسكربت</a>.
</p>

<p>
	احفظ الملف البرمجي الذي أنشأته واخرج من المحرِّر عن طريق الضغط على CTRL + X وتأكيد الخروج بالضغط على المفتاح Y عندما يطلب منك.
</p>

<p>
	شغّل البرنامج الآن وستُطالب بإدخال اسمك، لذا أدخله واضغط على ENTER، وقد لا يكون الخرج هو بالضبط ما تتوقعه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_52" style="">
<span class="typ">Please</span><span class="pln"> enter your name</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Sammy</span><span class="pln">
</span><span class="typ">Hi</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"> I</span><span class="str">'m Go!</span></pre>

<p>
	بدلًا من طباعة Hi, Sammy! I'm Go!‎، هناك سطر فاصل بعد الاسم مباشرةً، إذ التقط البرنامج جميع ضغطات المفاتيح بما في ذلك المفتاح ENTER الذي ضغطنا عليه لإخبار البرنامج بالمتابعة، لذا تكمن المشكلة في السلسلة، إذ يؤدي الضغط على المفتاح الإدخال ENTER إلى إنشاء رمز خاص يُنشئ سطرًا جديدًا وهو الرمز <code>n\</code>.
</p>

<p>
	افتح الملف لإصلاح المشكلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_54" style="">
<span class="pln">$ nano greeting</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	أضف السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_56" style="">
<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="pun">...</span></pre>

<p>
	ثم السطر التالي:
</p>

<pre class="ipsCode">
name = strings.TrimSpace(name)
</pre>

<p>
	استخدمنا هنا الدالة <code>TrimSpace</code> من الحزمة <code>strings</code> في مكتبة جو القياسية على السلسلة التي التقطتها باستخدام <code>fmt.Scanln</code>، إذ تزيل الدالة <code>strings.TrimSpace</code> محارف المسافة space characters بما في ذلك الأسطر الجديدة من بداية السلسلة ونهايتها، إذًا ستُزيل محرف السطر الجديد في نهاية السلسلة التي أُنشِئت عند الضغط على ENTER.
</p>

<p>
	ستحتاج لاستخدام الحزمة <code>strings</code> إلى استيرادها في الجزء العلوي من البرنامج.
</p>

<p>
	ضع ما يلي ضمن البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_59" 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="pun">)</span></pre>

<p>
	أضف السطر التالي لاستيراد الحزمة <code>strings</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_62" 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></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_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="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">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Please 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">
    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">
    fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="str">"Hi, %s! I'm Go!"</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الملف البرمجي الذي أنشأته واخرج من المحرِّر عن طريق الضغط على الاختصار CTRL + X وتأكيد الخروج بالضغط على الزر Y عندما يطلب منك.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_66" style="">
<span class="pln">$ go run greeting</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4735_68" style="">
<span class="typ">Please</span><span class="pln"> enter your name</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Sammy</span><span class="pln">
</span><span class="typ">Hi</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pun">!</span><span class="pln"> I</span><span class="str">'m Go!</span></pre>

<p>
	أصبح لديك الآن برنامج جو يأخذ مدخلات من المستخدِم ويطبعها على الشاشة.
</p>

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

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

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-write-your-first-program-in-go" rel="external nofollow">How To Write Your First Program in Go </a> لصاحبه Gopher Guides.
</p>

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

<ul>
<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%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%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/" rel="">بناء خادم بروتوكول التحكم في الإرسال TCP متزامن في لغة البرمجة Go</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1788</guid><pubDate>Mon, 12 Dec 2022 16:05:01 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x644;&#x63A;&#x629; &#x62C;&#x648; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x628;&#x64A;&#x626;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62D;&#x644;&#x64A;&#x629; &#x639;&#x644;&#x649; &#x648;&#x64A;&#x646;&#x62F;&#x648;&#x632;</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6365fa250b91b_3---------.png.c45bf1a15b0145d2b618ac4c1366f588.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="">جو Go</a> هي لغة برمجة حديثة ذات قواعد syntax عالية المستوى على غرار <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/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a> و<a href="https://academy.hsoub.com/programming/ruby/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%b1%d9%88%d8%a8%d9%8a-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d9%8a%d8%a9-r244/" rel="">روبي</a> و<a href="https://academy.hsoub.com/programming/javascript/%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-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافا سكربت</a>، وقد طوّرتها شركة جوجل Google في عام 2007 لتكون ملائمة لنوعية احتياجات جوجل الحسابية من حيث <a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%81%D8%B5%D9%84-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D9%81-compilation-%D9%81%D9%8A-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r976/" rel="">التصريف compilation</a> السريع وسهولة البرمجة والتنفيذ الفعّال. تعتبر جو لغة بسيطة جدًا من ناحية القواعد، فعدد الكلمات المفتاحية بها والأنواع الأساسية فيها ضئيل مقارنة بباقي اللغات، كما أنها تقلل كثيرًا من فكرة وجود طرق متعددة لتنفيذ مهمة ما، حتى أنها لا تحتوي على حلقة while وتقتصر فقط على حلقة for مما يجعل هذه اللغة سهلة التعلم ومناسبة للمبرمجين الجدد والخبراء ويميّزها عن باقي اللغات. تعالج جو عمليات التزامن بشكل مبتكر، بالإضافة إلى توفير الأدوات اللازمة لبناء ثنائيات محلية native binaries (برامج تنفيذية executables أو مكتبات shared libraries) لاستخدامها في منصات وأماكن أخرى.
</p>

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

<p>
	سترشدك هذه المقالة إلى كيفية تثبيت جو على جهاز محلي <a href="https://academy.hsoub.com/apps/operating-systems/windows/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-windows-10-r172/" rel="">بنظام تشغيل ويندوز 10</a> وإعداد بيئة برمجة باستخدام <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>

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

<p>
	جهاز مثبت عليه نظام ويندوز 10 مع إمكانية الوصول على أساس مدير والاتصال <a href="https://academy.hsoub.com/devops/networking/%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r571/" rel="">بالانترنت</a>.
</p>

<h2>
	الخطوة 1: فتح وتهيئة PowerShell
</h2>

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

<p>
	يُعَدّ PowerShell برنامجًا من مايكروسوفت يوفر واجهةً لصدفة سطر الأوامر، إذ تُنفَّذ المهام الإدارية عن طريق تشغيل أوامر cmdlets أي command-lets، وهي أصناف Classes متخصصة من إطار العمل NET. الذي يمكنه تنفيذ العمليات، وقد أصبح PowerShell مفتوح المصدر في عام 2016، وهو متوفر الآن على أطر العمل لكل من نظامَي ويندوز ويونكس UNIX بما في ذلك ماك Mac و<a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">لينكس Linux</a>.
</p>

<p>
	يمكنك النقر بزر الفأرة الأيمن فوق رمز قائمة ابدأ في الزاوية اليسرى السفلية من شاشتك للعثور على PowerShell على جهازك، ثم انقر فوق بحث واكتب PowerShell في شريط البحث، ثم انقر بزر الفأرة الأيمن فوق Windows PowerShell، ولأسباب تتعلق بهذه المقالة يُرجى فتحه على أساس مسؤول -أو مدير- من خلال اختيار Run as Administrator، وعندما ينبثق لك مربع حوار سيسألك هل تريد السماح لهذا التطبيق بإجراء تغييرات على جهاز الكمبيوتر الخاص بك؟ انقر فوق نعم yes، وبعد إجراء ما ذكرناه ستظهر لك النافذة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111471" href="https://academy.hsoub.com/uploads/monthly_2022_11/Win10SetUp.png.37d0e297b9c4f6508e12f0827efbf100.png" rel=""><img alt="فتح وتهيئة PowerShell" class="ipsImage ipsImage_thumbnailed" data-fileid="111471" data-unique="h9il7vieq" src="https://academy.hsoub.com/uploads/monthly_2022_11/Win10SetUp.thumb.png.dc423ae4b45a710e0542a021af0fa875.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	انتقل الآن إلى مجلد النظام من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_19" style="">
<span class="pln">$ cd </span><span class="pun">~</span></pre>

<p>
	سينقلك تنفيذ هذا الأمر إلى المجلد PS C:\Users\sammy.
</p>

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

<ul>
<li>
		المُقيّد Restricted: هي سياسة التنفيذ الافتراضية، وفي هذا الوضع لن تتمكن من تشغيل البرامج النصية scripts، وسيعمل PowerShell فقط على أساس صدفة تفاعلية مع هذه البرامج.
	</li>
	<li>
		الموقّع AllSigned: سيمكنك هذا الوضع من تشغيل جميع البرامج النصية وملفات الضبط الموقَّعة عبر <a href="https://ar.wikipedia.org/wiki/%D8%AA%D9%88%D9%82%D9%8A%D8%B9_%D8%B1%D9%82%D9%85%D9%8A" rel="external nofollow">التوقيع الرقمي</a> بواسطة ناشر موثوق، مما يعني أنه من المحتمل أن تٌعرِّض جهازك لخطر تشغيل البرامج النصية الضارة التي وقّع عليها ناشر موثوق به.
	</li>
	<li>
		الموقّعة عن بعد RemoteSigned: يتيح لك تشغيل البرامج النصية وملفات الضبط المُحمّلة من الإنترنت والموقَّعة من قِبل ناشرين موثوقين، أي أنه يعرّض جهازك للخطر أيضًا إذا كانت هذه البرامج النصية الموثوقة ضارة.
	</li>
	<li>
		بدون قيود Unrestricted: ستُشغَّل جميع البرامج النصية وملفات الضبط التي نُزِّلت من الإنترنت عند تأكيدك أنّ الملف قد نُزِّل من الإنترنت، وهنا لا يلزم وجود توقيع رقمي، وبالتالي فإنك تُعرّض جهازك لخطر تشغيل البرامج النصية غير الموقّعة والتي من المحتمل أن تكون ضارةً.
	</li>
</ul>
<p>
	سنعتمد في هذه المقال على مستوى RemoteSigned في سياسة التنفيذ للمستخدِم الحالي، وبالتالي سيمنح PowerShell إمكانية قبول البرامج النصية الموثوقة دون الحاجة إلى جعل الأذونات واسعةً أكثر مثل المستوى بدون قيود.
</p>

<p>
	نفّذ ما يلي ضمن PowerShell:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_21" style="">
<span class="pln">$ </span><span class="typ">Set</span><span class="pun">-</span><span class="typ">ExecutionPolicy</span><span class="pln"> </span><span class="pun">-</span><span class="typ">Scope</span><span class="pln"> </span><span class="typ">CurrentUser</span></pre>

<p>
	سيطالبك PowerShell بعد ذلك بتقديم سياسة تنفيذ، لذا أدخل ما يلي لاستخدام RemoteSigned:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_23" style="">
<span class="pln">$ </span><span class="typ">RemoteSigned</span></pre>

<p>
	سيُطلب منك تأكيد التغيير في سياسة التنفيذ بعد الضغط على ENTER، لذا اكتب المحرف <code>y</code> للسماح بتنفيذ التغييرات، كما يمكنك التأكد من نجاح ذلك من خلال الاستعلام عن الأذونات الحالية كما يلي:
</p>

<pre class="ipsCode">
$ Get-ExecutionPolicy -List
</pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_25" style="">
<span class="pln">        </span><span class="typ">Scope</span><span class="pln"> </span><span class="typ">ExecutionPolicy</span><span class="pln">
        </span><span class="pun">-----</span><span class="pln"> </span><span class="pun">---------------</span><span class="pln">
</span><span class="typ">MachinePolicy</span><span class="pln">       </span><span class="typ">Undefined</span><span class="pln">
   </span><span class="typ">UserPolicy</span><span class="pln">       </span><span class="typ">Undefined</span><span class="pln">
      </span><span class="typ">Process</span><span class="pln">       </span><span class="typ">Undefined</span><span class="pln">
  </span><span class="typ">CurrentUser</span><span class="pln">    </span><span class="typ">RemoteSigned</span><span class="pln">
 </span><span class="typ">LocalMachine</span><span class="pln">       </span><span class="typ">Undefined</span></pre>

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

<h2>
	الخطوة 2 - تثبيت مدير الحزم شوكولاتي Chocolatey
</h2>

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

<p>
	يُعَدّ شوكولاتي Chocolatey مدير حزم يمكن التفاعل معه من خلال سطر أوامر ومُصمَّم لنظام التشغيل ويندوز ويعمل مثل apt-get على لينكس، كما يُعَدّ <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D8%A7%D9%84%D9%85%D9%82%D8%B5%D9%88%D8%AF-%D8%A8%D9%85%D8%B5%D8%B7%D9%84%D8%AD-%D9%85%D9%81%D8%AA%D9%88%D8%AD-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-open-source%D8%9F-r885/" rel="">برمجية مفتوحة المصدر</a> يساعدك على تثبيت التطبيقات والأدوات بسرعة، وستتعلم في هذه المقالة كيفية استخدامه لتنزيل ما تحتاجه لبيئة التطوير الخاصة بك.
</p>

<p>
	اقرأ البرنامج النصي أو السكربت قبل تثبيته لتؤكِّد على أنك موافق على التغييرات التي سيجريها على جهازك، ولإنجاز ذلك استخدم <a href="https://academy.hsoub.com/programming/c-sharp/dotnet/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-dot-net-r943/" rel="">إطار عمل NET.</a> لتنزيل وعرض البرنامج شوكولاتي ضمن نافذة الطرفية.
</p>

<p>
	ابدأ بإنشاء كائن WebClient اسمه <code>script$</code> والذي يشارك إعدادات الاتصال بالإنترنت مع Internet Explorer:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5438_29" style="">
<span class="pln">$ $script </span><span class="pun">=</span><span class="pln"> </span><span class="typ">New</span><span class="pun">-</span><span class="typ">Object</span><span class="pln"> </span><span class="typ">Net</span><span class="pun">.</span><span class="typ">WebClient</span></pre>

<p>
	ألق نظرةً على الخيارات المتاحة عن طريق تمرير كائن <code>script$</code> مع المحرف <code>|</code> إلى الصنف <code>Get-Member</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_33" style="">
<span class="pln">$ $script </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Get</span><span class="pun">-</span><span class="typ">Member</span></pre>

<p>
	سيؤدي ذلك إلى عرض جميع الأعضاء -أي الخصائص والدوال- الخاصة بالكائن WebClient:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_35" style="">
<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><span class="pln">secondary_label </span><span class="typ">Snippet</span><span class="pln"> of </span><span class="typ">Output</span><span class="pun">]</span><span class="pln">
</span><span class="typ">DownloadFileAsync</span><span class="pln">         </span><span class="typ">Method</span><span class="pln">  </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">DownloadFileAsync</span><span class="pun">(</span><span class="pln">uri address</span><span class="pun">,</span><span class="pln"> string fileName</span><span class="pun">),</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">DownloadFileAsync</span><span class="pun">(</span><span class="pln">ur</span><span class="pun">...</span><span class="pln">
</span><span class="typ">DownloadFileTaskAsync</span><span class="pln">     </span><span class="typ">Method</span><span class="pln">  </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Threading</span><span class="pun">.</span><span class="typ">Tasks</span><span class="pun">.</span><span class="typ">Task</span><span class="pln"> </span><span class="typ">DownloadFileTaskAsync</span><span class="pun">(</span><span class="pln">string address</span><span class="pun">,</span><span class="pln"> string fileNa</span><span class="pun">...</span><span class="pln">
</span><span class="typ">DownloadString</span><span class="pln">            </span><span class="typ">Method</span><span class="pln">  string </span><span class="typ">DownloadString</span><span class="pun">(</span><span class="pln">string address</span><span class="pun">),</span><span class="pln"> string </span><span class="typ">DownloadString</span><span class="pun">(</span><span class="pln">uri address</span><span class="pun">)</span><span class="pln"> </span><span class="com">#method we will use</span><span class="pln">
</span><span class="typ">DownloadStringAsync</span><span class="pln">       </span><span class="typ">Method</span><span class="pln">  </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">DownloadStringAsync</span><span class="pun">(</span><span class="pln">uri address</span><span class="pun">),</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">DownloadStringAsync</span><span class="pun">(</span><span class="pln">uri address</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Sy</span><span class="pun">...</span><span class="pln">
</span><span class="typ">DownloadStringTaskAsync</span><span class="pln">   </span><span class="typ">Method</span><span class="pln">     </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Threading</span><span class="pun">.</span><span class="typ">Tasks</span><span class="pun">.</span><span class="typ">Task</span><span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln"> </span><span class="typ">DownloadStringTaskAsync</span><span class="pun">(</span><span class="pln">string address</span><span class="pun">),</span><span class="pln"> </span><span class="typ">Sy</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>
	بالنظر إلى الخرج، يمكنك تحديد طريقة DownloadString المستخدَمة لعرض البرنامج النصي أو السكربت والتوقيع في نافذة PowerShell، واستخدِم هذه الطريقة لفحص البرنامج النصي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_37" style="">
<span class="pln">$ $script</span><span class="pun">.</span><span class="typ">DownloadString</span><span class="pun">(</span><span class="str">"https://chocolatey.org/install.ps1"</span><span class="pun">)</span></pre>

<p>
	ثبّت شوكولاتي بعد فحص البرنامج النصي بكتابة ما يلي في PowerShell:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_39" style="">
<span class="pln">$ iwr https</span><span class="pun">:</span><span class="com">//chocolatey.org/install.ps1 -UseBasicParsing | iex</span></pre>

<p>
	يسمح لك أمر <code>iwr</code> -وهو أحد أوامر cmdlet- أو <code>Invoke-WebRequest</code> باستخراج البيانات من الويب، إذ سيؤدي ذلك إلى تمرير البرنامج النصي إلى <code>iex</code>، أو <code>Invoke-Expression cmdlet</code>، والذي سينفذ محتويات البرنامج النصي ويشغّل عملية تثبيت مدير حزم شوكولاتي.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_41" style="">
<span class="pln">$ choco upgrade chocolatey</span></pre>

<p>
	يمكنك تثبيت ما تبقى من أدوات لتجهيز بيئة برمجة جو بعد تثبيت مدير الحزم.
</p>

<h2>
	الخطوة 3 - تثبيت محرر النصوص Nano (خطوة اختيارية)
</h2>

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

<p>
	استخدم شوكولاتي لتثبيت نانو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_43" style="">
<span class="pln">$ choco install </span><span class="pun">-</span><span class="pln">y nano</span></pre>

<p>
	تُستخدَم الراية <code>y-</code> للتأكيد التلقائي -أي الموافقة- على تشغيل البرنامج النصي.
</p>

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

<h2>
	الخطوة 4 - تثبيت جو
</h2>

<p>
	ستستخدِم شوكولاتي كما في الخطوة السابقة لتثبيت جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_45" style="">
<span class="pln">$ choco install </span><span class="pun">-</span><span class="pln">y golang</span></pre>

<p>
	<strong>ملاحظة</strong>: كلمة go عبارة عن كلمة صغيرة وتتطابق مع العديد من الحزم، وبالتالي أصبح من الشائع استخدام كلمة golang على أساس مصطلح لتثبيت الحِزم وعند البحث على الإنترنت عن مقالات متعلقة بلغة جو، وقد وُلِّد مصطلح Golang من رابط الموقع الرسمي لجو وهو golang.org.
</p>

<p>
	سيثبّت PowerShell جو الآن وستشاهد الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_47" style="">
<span class="typ">Environment</span><span class="pln"> </span><span class="typ">Vars</span><span class="pln"> </span><span class="pun">(</span><span class="pln">like PATH</span><span class="pun">)</span><span class="pln"> have changed</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Close</span><span class="pun">/</span><span class="pln">reopen your shell to
see the changes </span><span class="pun">(</span><span class="pln">or in powershell</span><span class="pun">/</span><span class="pln">cmd</span><span class="pun">.</span><span class="pln">exe just type </span><span class="pun">`</span><span class="pln">refreshenv</span><span class="pun">`).</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> install of golang was successful</span><span class="pun">.</span><span class="pln">
 </span><span class="typ">Software</span><span class="pln"> installed as </span><span class="str">'msi'</span><span class="pun">,</span><span class="pln"> install location is likely </span><span class="kwd">default</span><span class="pun">.</span><span class="pln">

</span><span class="typ">Chocolatey</span><span class="pln"> installed </span><span class="lit">1</span><span class="pun">/</span><span class="lit">1</span><span class="pln"> packages</span><span class="pun">.</span><span class="pln">
</span><span class="typ">See</span><span class="pln"> the log </span><span class="kwd">for</span><span class="pln"> details </span><span class="pun">(</span><span class="pln">C</span><span class="pun">:</span><span class="pln">\ProgramData\chocolatey\logs\chocolatey</span><span class="pun">.</span><span class="pln">log</span><span class="pun">).</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_49" style="">
<span class="pln">$ go version</span></pre>

<p>
	سترى خرجًا مُشابهًا للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_51" style="">
<span class="pln">go version go1</span><span class="pun">.</span><span class="lit">12.1</span><span class="pln"> windows</span><span class="pun">/</span><span class="pln">amd643</span><span class="pun">.</span><span class="lit">7.0</span></pre>

<p>
	حيث يعرض لك تفاصيل النسخة الحالية المثبتة على حاسبك من جو. يمكنك الآن إعداد مساحة عمل لمشاريع التطوير الخاصة بك.
</p>

<h2>
	الخطوة 5 - إنشاء مساحة العمل الخاصة بك لبناء مشاريع جو
</h2>

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

<ul>
<li>
		src: مجلد ستوضَع فيه ملفات جو المصدرية وهي الملفات التي المكتوبة والمنشأة باستخدام لغة جو، إذ يستخدِمها مُصرِّف جو لإنشاء ملفات قابلة للتنفيذ وهي ملفات ثنائية يمكن تشغيلها على نظامك لتنفيذ المهام التي تتضمنها).
	</li>
	<li>
		bin: مجلد ستوضَع فيه الملفات الثنائية التي أُنشِئت وثبِّتَت بواسطة أدوات جو؛ وبعبارة أخرى هي البرامج التي المصرَّفة بواسطة الشيفرة المصدرية الخاصة بك أو غيرها من التعليمات البرمجية المصدرية المرتبطة بجو والتي قد نزِّلت.
	</li>
</ul>
<p>
	من المحتمل أن يحتوي المجلد الفرعي src على عدة مستودعات للتحكم في الإصدارات مثل Git و Mercurial و Bazaar، وهذا يسمح لك باستيراد أساسي canonical import للشيفرة في مشروعك وهو عملية استيراد تشير إلى حزمة مؤهلة وجاهزة بالكامل مثل github.com/digitalocean/godo.
</p>

<p>
	سترى مجلدات مثل github.com أو golang.org عندما يستورد برنامجك مكتبات خارجية، فإذا كنت تستخدِم -أو لديك- شيفرات برمجية على إحدى المواقع مثل GitHub، فستضع أيضًا هذه المشاريع أو الملفات المصدرية ضمن هذا المجلد وستتعرّف على ذلك بعد قليل.
</p>

<p>
	ستبدو مساحة العمل النموذجية هكذا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_53" 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"> buffalo                                      </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> dlv                                          </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> packr                                        </span><span class="com"># أمر تنفيذي</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"> digitalocean
            </span><span class="pun">└──</span><span class="pln"> godo
                </span><span class="pun">├──</span><span class="pln"> </span><span class="pun">.</span><span class="pln">git                            </span><span class="com"># البيانات الوصفية لمستودع جيت</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account</span><span class="pun">.</span><span class="pln">go                      </span><span class="com"># ملف الحزمة</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account_test</span><span class="pun">.</span><span class="pln">go             </span><span class="com"># اختبار ملف الحزمة</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"> timestamp</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">├──</span><span class="pln"> timestamp_test</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">└──</span><span class="pln"> util
                    </span><span class="pun">├──</span><span class="pln"> droplet</span><span class="pun">.</span><span class="pln">go
                    </span><span class="pun">└──</span><span class="pln"> droplet_test</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	يُعَدّ المجلد الافتراضي لمساحة العمل في جو بدءًأ من الإصدار 1.8المجلد الرئيسي home للمستخدِم الذي يحتوي على مجلد فرعي باسم go أي HOME/go$، فإذا كنت تستخدِم إصدارًا أقدم من 1.8، فمن الأفضل الاستمرار في استخدام الموقع HOME/go$ لمساحة عملك.
</p>

<p>
	نفّذ الأمر التالي للانتقال إلى المجلد HOME$:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_55" style="">
<span class="pln">$ cd $HOME</span></pre>

<p>
	أنشئ بعدها مجلدًا لبيئة العمل بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_57" style="">
<span class="pln">$ mkdir go</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">,</span><span class="pln"> go</span><span class="pun">/</span><span class="pln">src</span></pre>

<p>
	سيؤدي ذلك إلى إنشاء بنية المجلد التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_59" style="">
<span class="pun">└──</span><span class="pln"> $HOME
    </span><span class="pun">└──</span><span class="pln"> go
        </span><span class="pun">├──</span><span class="pln"> bin
        </span><span class="pun">└──</span><span class="pln"> src</span></pre>

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

<p>
	يجب أن يكون متغير البيئة <code>GOPATH$</code> قد حُدّدَ فعلًا نظرًا لأنك استخدَمت شوكولاتي في عملية التثبيت، ويمكنك التحقق من ذلك بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_61" style="">
<span class="pln">$ $env</span><span class="pun">:</span><span class="pln">GOPATH</span></pre>

<p>
	يجب أن ترى الخرج التالي مع اسم المستخدِم الخاص بك بدلًا من sammy:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_63" style="">
<span class="pln">C</span><span class="pun">:</span><span class="pln">\Users\sammy\go</span></pre>

<p>
	عندما يُصرِّف ويثبّت جو الأدوات، فسيضعها في المجلد GOPATH/bin$، وللراحة فإنه من الشائع إضافة المجلد الفرعي bin الخاص بمساحة العمل إلى <code>‎$PATH</code>، ويمكنك إنجاز ذلك من خلال الأمر <code>setx</code> في PowerShell:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_65" style="">
<span class="pln">$ setx PATH </span><span class="str">"$($env:path);$GOPATH\bin"</span></pre>

<p>
	سيسمح لك ذلك بتشغيل أيّ برامج تصرّفها أو تنزّلها عبر أدوات جو في أيّ مكان على نظامك.
</p>

<p>
	الآن وبعد أن أنشأت المجلد الجذر لمساحة العمل وضبطت مجموعة متغيرات البيئة <code>GOPATH$</code> الخاصة بك، فقد أصبح بإمكانك إنشاء مشاريعك المستقبلية باستخدام بنية المجلد التالية، ويفترض هذا المثال أنك تستخدِم موقع GitHub لاستضافة مشروعك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_67" 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">username</span><span class="pun">/</span><span class="pln">project</span></pre>

<p>
	إذا كنت تعمل على مشروع <a href="https://github.com/digitalocean/godo%D8%8C" ipsnoembed="false" rel="external nofollow">https://github.com/digitalocean/godo،</a> فسيُخزَّن في المجلد التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_69" 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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_72" style="">
<span class="pln">$ go get github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	<strong>ملاحظة</strong>: إذا لم يكن جيت git مُثبّتًا لديك، فسيفتح ويندوز مربع حوار يسألك عما إذا كنت تريد تثبيته، وعندها انقر فوق نعم yes للمتابعة واتبع إرشادات التثبيت.
</p>

<p>
	يمكنك أيضًا التحقق من نجاح عملية التنزيل من خلال سرد محتويات المجلد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_74" style="">
<span class="pln">$ ls </span><span class="pun">-</span><span class="pln">l $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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	يجب أن تشاهد خرجًا يشبه الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_76" style="">
<span class="pln">    </span><span class="typ">Directory</span><span class="pun">:</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">\Users\sammy\go\src\github</span><span class="pun">.</span><span class="pln">com\digitalocean\godo


</span><span class="typ">Mode</span><span class="pln">                </span><span class="typ">LastWriteTime</span><span class="pln">       </span><span class="typ">Length</span><span class="pln"> </span><span class="typ">Name</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><span class="pln">
d</span><span class="pun">-----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM             util
</span><span class="pun">-</span><span class="pln">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM             </span><span class="lit">9</span><span class="pln"> </span><span class="pun">.</span><span class="pln">gitignore
</span><span class="pun">-</span><span class="pln">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM             </span><span class="lit">69</span><span class="pln"> </span><span class="pun">.</span><span class="pln">travis</span><span class="pun">.</span><span class="pln">yml
</span><span class="pun">-</span><span class="pln">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM         </span><span class="lit">1592</span><span class="pln"> account</span><span class="pun">.</span><span class="pln">go
</span><span class="pun">-</span><span class="pln">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM         </span><span class="lit">1679</span><span class="pln"> account_test</span><span class="pun">.</span><span class="pln">go
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">2892</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> CHANGELOG</span><span class="pun">.</span><span class="pln">md
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">1851</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> CONTRIBUTING</span><span class="pun">.</span><span class="pln">md
</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">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM         </span><span class="lit">5076</span><span class="pln"> vpcs</span><span class="pun">.</span><span class="pln">go
</span><span class="pun">-</span><span class="pln">a</span><span class="pun">----</span><span class="pln">        </span><span class="lit">4</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2019</span><span class="pln">   </span><span class="lit">2</span><span class="pun">:</span><span class="lit">59</span><span class="pln"> PM         </span><span class="lit">4309</span><span class="pln"> vpcs_test</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<h2>
	الخطوة 6 - إنشاء برنامج بسيط
</h2>

<p>
	ستنشئ برنامجًا بسيطًا بلغة جو Go يطبع العبارة “Hello, World!‎” بغية اختبار مساحة العمل والتعرف أكثر على جو، كما ستنشئ هنا ملفًا مصدريًا واحدًا لجو وليس مشروعًا متكاملًا، لذا لا داعي لأن تكون ضمن مساحة العمل الخاصة بك لإنجاز ذلك.
</p>

<p>
	افتح محرر نصوص سطر الأوامر نانو من المجلد الرئيسي وأنشئ ملفًا جديدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_78" style="">
<span class="pln">$ nano hello</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	اكتب برنامجك في الملف الجديد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_80" 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">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستستخدم هذه الشيفرة حزمة fmt وستستدعي الدالة <code>Println</code> لطباعة Hello, World!‎ الممررة على أساس وسيط للدالة.
</p>

<p>
	اخرج الآن من المحرر nano بالضغط على مفتاحَي<code>CTRL+ X</code>، وعند مطالبتك بحفظ الملف، اضغط على <code>Y</code> ثم ENTER، ثم شغّل برنامج hello.go الذي أنشأته عند الخروج من nano والعودة إلى الصدَفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_84" style="">
<span class="pln">$ go run hello</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5438_86" style="">
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!</span></pre>

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

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

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

<p>
	ترجمة -وبتصرَُف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-go-and-set-up-a-local-programming-environment-on-windows-10" rel="external nofollow">How To Install Go and Set Up a Local Programming Environment on Windows 10</a> لصاحبه Gopher Guides.
</p>

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

<ul>
<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-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-r1766/" rel="">تثبيت لغة جو وإعداد بيئة برمجة محلية على أبونتو</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/apps/operating-systems/windows/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-10-r228/" rel="">بدء العمل مع ويندوز 10</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1768</guid><pubDate>Sat, 05 Nov 2022 06:16:47 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x644;&#x63A;&#x629; &#x62C;&#x648; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x628;&#x64A;&#x626;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62D;&#x644;&#x64A;&#x629; &#x639;&#x644;&#x649; &#x646;&#x638;&#x627;&#x645; &#x645;&#x627;&#x643; macOS</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6365f562bdd62_2-----------macOS.png.60fdeb58592de2f29dd4a1234ceda1f5.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="">جو Go</a> هي لغة برمجة حديثة ذات قواعد syntax عالية المستوى على غرار <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/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a> و<a href="https://academy.hsoub.com/programming/ruby/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%b1%d9%88%d8%a8%d9%8a-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d9%8a%d8%a9-r244/" rel="">روبي</a> و<a href="https://academy.hsoub.com/programming/javascript/%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-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافاسكربت</a>، وقد طوّرتها شركة جوجل Google في عام 2007 لتكون ملائمة لنوعية احتياجات جوجل الحسابية من حيث <a href="https://academy.hsoub.com/programming/c/%D8%A7%D9%84%D9%81%D8%B5%D9%84-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D9%81-compilation-%D9%81%D9%8A-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r976/" rel="">التصريف compilation</a> السريع وسهولة البرمجة والتنفيذ الفعّال. تعتبر جو لغة بسيطة جدًا من ناحية القواعد، فعدد الكلمات المفتاحية بها والأنواع الأساسية فيها ضئيل مقارنة بباقي اللغات، كما أنها تقلل كثيرًا من فكرة وجود طرق متعددة لتنفيذ مهمة ما، حتى أنها لا تحتوي على حلقة while وتقتصر فقط على حلقة for مما يجعل هذه اللغة سهلة التعلم ومناسبة للمبرمجين الجدد والخبراء ويميّزها عن باقي اللغات. تعالج جو عمليات التزامن بشكل مبتكر، بالإضافة إلى توفير الأدوات اللازمة لبناء ثنائيات محلية native binaries (برامج تنفيذية executables أو مكتبات shared libraries) لاستخدامها في منصات وأماكن أخرى.
</p>

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

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

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

<p>
	ستحتاج إلى حاسب يعمل بنظام ماك macOS مع إمكانية وصول إدارية administrative access واتصال <a href="https://academy.hsoub.com/devops/networking/%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r571/" rel="">بالإنترنت</a>.
</p>

<h2>
	الخطوة 1 - فتح الطرفية Terminal
</h2>

<p>
	سننجز عملية التثبيت والإعداد من خلال <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="">سطر الأوامر command line</a> وهو معروف أيضًا باسم الصدَفة shell وهو وسيلة تخاطب مع الحاسوب عبر كتابة الأوامر له والذي يُمكّنك من تعديل وأتمتة العديد من المهام التي تقوم بها على جهاز الحاسوب كل يوم وهو أداة أساسية لمطورِي البرامج.
</p>

<p>
	تُعَدّ طرفية نظام ماك تطبيقًا يمكنك استخدامه للوصول إلى واجهة سطر الأوامر، ومثل أي تطبيق آخر يمكنك العثور عليه بالذهاب إلى Finder ثم الانتقال إلى مجلد التطبيقات Applications ثم إلى مجلد الأدوات المساعدة Utilities، وانقر بعد ذلك نقرًا مزدوجًا فوق أيقونة الطرفية.
</p>

<p>
	يمكنك أيضًا العثور على الطرفية من خلال فتح Spotlight عن طريق الضغط باستمرار على مفتاحَي CMD + SPACE وكتابتها في المربع الذي يظهر.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2024_01/MacOSXSetUp.png.e7901657dcc5fc453618d1e1fa7a9497.png" data-fileid="142829" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="142829" data-ratio="65.05" data-unique="kswa6fa6p" style="width: 598px; height: auto;" width="900" alt="MacOSXSetUp.png" src="https://academy.hsoub.com/uploads/monthly_2024_01/MacOSXSetUp.thumb.png.7245c335389637fccd9a4d6715a2dbb4.png"></a>
</p>

<p>
	هناك العديد من الأوامر الخاصة بالطرفية والتي يمكنك تعلّمها من مقال <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B7%D8%B1%D9%81%D9%8A%D9%91%D8%A9-%D9%84%D9%8A%D9%86%D9%83%D8%B3-linux-terminal-r18/" rel="">مدخل إلى طرفيّة لينكس Linux Terminal</a>، وبعد فتح تطبيق الطرفية يمكنك تحميل حزمة أدوات المطور<a href="https://developer.apple.com/xcode/" rel="external nofollow">Xcode</a> وتثبيتها، إذ ستحتاجها لتثبيت جو.
</p>

<h2>
	الخطوة 2 - تثبيت Xcode
</h2>

<p>
	تُعَدّ Xcode بيئة تطوير متكاملة integrated development environment أو IDE اختصارًا، وتحتوي على أدوات تطوير البرامج لنظام ماك، كما يمكنك التحقق مما إذا كان Xcode مثبتًا بالفعل عن طريق كتابة ما يلي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_46" style=""><span class="pln">$ xcode</span><span class="pun">-</span><span class="pln">select </span><span class="pun">-</span><span class="pln">p</span></pre>

<p>
	يعني الخرج التالي أنّ Xcode مُثبّت:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_48" style=""><span class="pun">/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Developer</span><span class="pun">/</span><span class="typ">CommandLineTools</span></pre>

<p>
	إذا تلقيت خطأً ما، فثبّت Xcode من متجر <a href="https://itunes.apple.com/us/app/xcode/id497799835?mt=12&amp;ign-mpt=uo%3D2" rel="external nofollow">App Store</a> واضغط على زر قبول الخيارات الافتراضية.
</p>

<p>
	عُد إلى نافذة الطرفية بعد تثبيت Xcode، وبعد ذلك ستحتاج إلى تثبيت تطبيق أدوات سطر الأوامر Command Line Tools الذي يخص Xcode عن طريق كتابة الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_50" style=""><span class="pln">$ xcode</span><span class="pun">-</span><span class="pln">select </span><span class="pun">--</span><span class="pln">install</span></pre>

<p>
	إلى هنا تكون قد ثبّت كل من Xcode وتطبيق Command Line Tools -أدوات سطر الأوامر الخاص به بالكامل، ويمكنك الآن تثبيت مدير الحزم Homebrew.
</p>

<h2>
	الخطوة 3 - تثبيت وإعداد Homebrew
</h2>

<p>
	على الرغم من احتواء طرفية نظام ماك على الكثير من الوظائف المفيدة مثل تلك الموجودة في أنظمة <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">لينكس</a> ويونكس، إلا أنها لا تحتوي على مدير حزم الذي يُعَدّ مجموعةً من الأدوات البرمجية التي تعمل على أتمتة عمليات التثبيت بما في ذلك التثبيت الأولي للبرامج وترقيتها وضبطها وإزالتها حسب الحاجة، كما يحتفظ بالحزم المثبَّتة في موقع مركزي وحسب التنسيقات الشائعة.
</p>

<p>
	يزوِّد Homebrew نظام ماك بنظام إدارة حزمة برمجيات مجانية <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D8%A7%D9%84%D9%85%D9%82%D8%B5%D9%88%D8%AF-%D8%A8%D9%85%D8%B5%D8%B7%D9%84%D8%AD-%D9%85%D9%81%D8%AA%D9%88%D8%AD-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-open-source%D8%9F-r885/" rel="">ومفتوحة المصدر</a> يعمل على تبسيط عملية تثبيت الحزم على نظام ماك، كما يمكنك تثبيته من خلال تنفيذ الأمر التالي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_20" style=""><span class="pln">$ </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">ruby </span><span class="pun">-</span><span class="pln">e </span><span class="str">"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"</span></pre>

<p>
	كُتب Homebrew باستخدام <a href="https://wiki.hsoub.com/Ruby" rel="external">لغة روبي Ruby</a>، لذلك سيعدّل مسار Ruby على حاسبك، كما سيسحب الأمر <code>curl</code> برمجيةً أو سكربتًا من <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> المحدد وسيطبع لك هذا السكربت رسالةً تشرح فيها ما الذي ستفعله وستطلب منك الإذن لتنفيذ ذلك، إذًا ستوفر لك تلك الرسائل إمكانية معرفة ما الذي ستنفّذه البرمجية وستمنحك الفرصة للتحقق والموافقة على التنفيذ.
</p>

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

<p>
	فيما يلي بعض الرايات flags المرتبطة بالأمر <code>curl</code>:
</p>

<ul>
	<li>
		الراية <code>f-</code> أو <code>fail--</code> تُخبر الطرفية بعدم تقديم مستند <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> عند حدوث أخطاء في <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a>.
	</li>
	<li>
		الراية <code>s-</code> أو <code>silent--</code> تُستخدَم لكتم الأمر <code>curl</code>، أي لن تظهر لك معلومات أثناء عملية التثبيت، وبالتالي لن تُظهِر لك مقياس التقدم، وعند دمج هذه الراية مع الراية <code>S-</code> أو<code>show-error --</code>، فسيُظهر لك <code>curl</code> رسالة خطأ في حالة الفشل.
	</li>
	<li>
		الراية <code>L-</code> أو <code>location curl--</code> ستُخبِر <code>curl</code> بأنه عليه إعادة طلب العنوان من المكان الجديد في حال أبلغ الخادم عن انتقال الصفحة المطلوبة إلى موقع مختلف.
	</li>
</ul>

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

<p>
	يجب عليك إنشاء أو فتح ملف ‎~/.bash_profile‎ باستخدام محرر نصوص سطر الأوامر nano من خلال الأمر <code>nano</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_24" style=""><span class="pln">$ nano </span><span class="pun">~/.</span><span class="pln">bash_profile</span></pre>

<p>
	اكتب الأمر التالي بعد فتح الملف في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_26" style=""><span class="kwd">export</span><span class="pln"> PATH</span><span class="pun">=/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:</span><span class="pln">$PATH</span></pre>

<p>
	اضغط الآن باستمرار على مفتاح CTRL + o لحفظ التغييرات، وعندما يُطلب منك ذلك اضغط على مفتاح RETURN، كما يمكنك الآن الخروج من nano بالضغط على مفتاحي CTRL + x.
</p>

<p>
	نشِّط هذه التغييرات عن طريق تنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_29" style=""><span class="pln">$ source </span><span class="pun">~/.</span><span class="pln">bash_profile</span></pre>

<p>
	بذلك ستدخل التغييرات التي أجريتها على متغير البيئة <code>PATH</code> حيّز التنفيذ، كما يمكنك التأكد من تثبيت Homebrew بنجاح عن طريق كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_57" style=""><span class="pln">$ brew doctor</span></pre>

<p>
	إذا لم تكن هناك حاجة إلى إجراء عمليات تحديث، فستحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_59" style=""><span class="typ">Your</span><span class="pln"> system is ready to brew</span><span class="pun">.</span></pre>

<p>
	بالنسبة لعمليات التحديث التي قد تُطالب بها، فربما تكون تحذيرًا لتشغيل أمر آخر مثل <code>brew update</code>، وذلك للتأكد من أنّ تثبيت Homebrew الخاص بك بدوره محدث.
</p>

<p>
	بعد تجهيز Homebrew يمكنك تثبيت جو.
</p>

<h2>
	الخطوة 4 - تثبيت جو
</h2>

<p>
	يمكنك البحث عن جميع الحزم المتاحة عن طريق Homebrew من خلال الأمر <code>brew search</code>، وهنا ستبحث عن الحزم أو الوحدات المتعلقة بجو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_61" style=""><span class="pln">$ brew search golang</span></pre>

<p>
	<strong>ملاحظة</strong>: لم يُستخدم في هذا المقال بحث brew باستخدام كلمة go، أي أننا لم نكتب <code>brew search go</code> لأنه يُعيد عددًا كبيرًا جدًا من النتائج، فكلمة <code>go</code> عبارة عن كلمة صغيرة وتتطابق مع العديد من الحزم، وبالتالي أصبح من الشائع استخدام كلمة <code>golang</code> على أساس مصطلح بحث، كما تُعَدّ هذه ممارسة شائعةً عند البحث على الإنترنت عن مقالات متعلقة بجو أيضًا، وقد وُلِد مصطلح Golang من عنوان موقع اللغة الرسمي golang.org.
</p>

<p>
	سيكون الخرج قائمةً من الحزم والوحدات المتعلقة بلغة جو كما ذكرنا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_63" style=""><span class="pln">golang    golang</span><span class="pun">-</span><span class="pln">migrate</span></pre>

<p>
	يمكنك الآن تثبيت لغة جو عبر تنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_65" style=""><span class="pln">$ brew install golang</span></pre>

<p>
	ستعطيك الطرفية ملاحظات تتعلق بتثبيت جو، وقد يستغرق التثبيت بضع دقائق قبل اكتمال التثبيت.
</p>

<p>
	اكتب ما يلي للتحقق من إصدار جو الذي ثبّته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_67" style=""><span class="pln">$ go version</span></pre>

<p>
	سيطبع الأمر السابق الإصدار المُثبت لديك من جو وسيكون الإصدار الحديث والمستقر.
</p>

<p>
	يمكنك لاحقًا تحديث جو من خلال تنفيذ الأوامر التالية لتحديث Homebrew ثم تحديث جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_69" style=""><span class="pln">$ brew update
$ brew upgrade golang</span></pre>

<p>
	سيحدِّث الأمر الأول صيغة Homebrew نفسها، وبالتالي ضمان حصولك على أحدث المعلومات للحزم التي تريد تثبيتها؛ أما الأمر الثاني فسيُحدّث الحزمة <code>golang</code> إلى أحدث إصدار متوفر.
</p>

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

<p>
	بعد تثبيت جو أصبحت جاهزًا لإنشاء مساحة عمل لمشاريع جو الخاصة بك.
</p>

<h2>
	الخطوة 5 - إنشاء مساحة العمل الخاصة بك لبناء مشاريع جو
</h2>

<p>
	الآن يمكنك المتابعة وإنشاء مساحة عمل البرمجة الخاصة بك بعد أن ثبّتََ Xcode و Homebrew و Go.
</p>

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

<ul>
	<li>
		src: ستوضع فيه ملفات جو المصدرية، وهي الملفات التي تُكتَب وتُنشأ باستخدام لغة جو، كما يستخدِمها مُصرِّف جو لإنشاء ملفات قابلة للتنفيذ (ملفات ثنائية يمكن تشغيلها على نظامك لتنفيذ المهام التي تتضمنها).
	</li>
	<li>
		bin: ستوضع فيه الملفات القابلة للتنفيذ التي أنشئت وثبِّتت بواسطة أدوات جو، وبعبارة أخرى هي البرامج التي تم تصريفها بواسطة الشيفرة المصدرية الخاصة بك أو غيرها من الشيفرة المصدرية المرتبطة بجو والتي جرى تحميلها.
	</li>
</ul>

<p>
	من المحتمل أن يحتوي المجلد src على عدة مستودعات للتحكم في الإصدارات مثل Git و Mercurial و Bazaar، ويسمح لك هذا باستيراد أساسي canonical import للشفرة في مشروعك، إذ يُعَدّ الاستيراد الأساسي عملية استيراد تشير إلى حزمة مؤهلة وجاهزة بالكامل مثل github.com/digitalocean/godo.
</p>

<p>
	سترى مجلدات مثل github.com أو golang.org عندما يستورد برنامجك مكتبات خارجية، فإذا كنت تستخدم -أو لديك- شيفرات برمجية على إحدى المواقع مثل GitHub، فستضع أيضًا هذه المشاريع أو ملفات المصدر ضمن هذا المجلد وستتعرّف على ذلك بعد قليل.
</p>

<p>
	ستبدو مساحة العمل النموذجية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_31" 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"> buffalo                                      </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> dlv                                          </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> packr                                        </span><span class="com"># أمر تنفيذي</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"> digitalocean
            </span><span class="pun">└──</span><span class="pln"> godo
                </span><span class="pun">├──</span><span class="pln"> </span><span class="pun">.</span><span class="pln">git                            </span><span class="com"># البيانات الوصفية لمستودع جيت</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account</span><span class="pun">.</span><span class="pln">go                      </span><span class="com"># ملف الحزمة</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account_test</span><span class="pun">.</span><span class="pln">go             </span><span class="com"># اختبار ملف الحزمة</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"> timestamp</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">├──</span><span class="pln"> timestamp_test</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">└──</span><span class="pln"> util
                    </span><span class="pun">├──</span><span class="pln"> droplet</span><span class="pun">.</span><span class="pln">go
                    </span><span class="pun">└──</span><span class="pln"> droplet_test</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	بدءًأ من الإصدار 1.8 يُعَدّ المجلد الافتراضي لمساحة العمل في جو هو المجلد الرئيسي home directory للمستخدِم الذي يحتوي على مجلد فرعي باسم go أي HOME/go$، فإذا كنت تستخدِم إصدارًا أقدم من 1.8، فمن الأفضل الاستمرار في استخدام الموقع HOME/go$ لمساحة عملك.
</p>

<p>
	نفِّذ الأمر التالي لإنشاء بنية مجلد لمساحة العمل الخاصة بك في جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_33" style=""><span class="pln">$ mkdir </span><span class="pun">-</span><span class="pln">p $HOME</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/{</span><span class="pln">bin</span><span class="pun">,</span><span class="pln">src</span><span class="pun">}</span></pre>

<p>
	يطلب الخيار <code>p-</code> من <code>mkdir</code> إنشاء جميع العناصر الرئيسية parents في المجلد حتى لو لم تكن موجودة حاليًا، كما يؤدي استخدام <code>{bin,src}</code> إلى إنشاء مجموعة من الوسائط لـ <code>mkdir</code> وإخباره بإنشاء كل من مجلدَي bin و src.
</p>

<p>
	سيؤدي ذلك إلى إنشاء بنية المجلد التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_35" style=""><span class="pun">└──</span><span class="pln"> $HOME
    </span><span class="pun">└──</span><span class="pln"> go
        </span><span class="pun">├──</span><span class="pln"> bin
        </span><span class="pun">└──</span><span class="pln"> src</span></pre>

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

<p>
	يمكن ضبط المتغير <code>GOPATH$</code> الخاص بك من خلال إضافة المتغيرات العامة إلى bash_profile./~.
</p>

<p>
	أولًا، افتح bash_profile./~ باستخدام nano أو محرر النصوص المفضل لديك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_37" style=""><span class="pln">$ nano </span><span class="pun">~/.</span><span class="pln">bash_profile</span></pre>

<p>
	اضبط المتغير <code>GOPATH$</code> الخاص بك من خلال إضافة ما يلي إلى الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_39" style=""><span class="kwd">export</span><span class="pln"> GOPATH</span><span class="pun">=</span><span class="pln">$HOME</span><span class="pun">/</span><span class="pln">go</span></pre>

<p>
	عندما يُصرّف ويثبّت جو الأدوات، فإنه سيضعها في المجلد GOPATH/bin$، ومن الشائع إضافة المجلد الفرعي bin/ الخاص بمساحة العمل إلى PATH في bash_profile./~:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_76" style=""><span class="kwd">export</span><span class="pln"> PATH</span><span class="pun">=</span><span class="pln">$PATH</span><span class="pun">:</span><span class="pln">$GOPATH</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	أضف الآن ما يلي إلى ملف bash_profile./~:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_78" style=""><span class="kwd">export</span><span class="pln"> GOPATH</span><span class="pun">=</span><span class="pln">$HOME</span><span class="pun">/</span><span class="pln">go
</span><span class="kwd">export</span><span class="pln"> PATH</span><span class="pun">=</span><span class="pln">$PATH</span><span class="pun">:</span><span class="pln">$GOPATH</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	سيسمح لك ذلك بتشغيل أية برامج تصرفها أو تحملها عبر أدوات جو في أيّ مكان على نظامك.
</p>

<p>
	نفّذ الأمر التالي لتحميل المتغيرات العامة وتحديث الصدَفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_80" style=""><span class="pln">$ </span><span class="pun">.</span><span class="pln"> </span><span class="pun">~/.</span><span class="pln">bash_profile</span></pre>

<p>
	يمكنك يمكنك التحقق من تحديث المتغير PATH$ باستخدام الأمر <code>echo</code> وقراءة الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_82" style=""><span class="pln">$ echo $PATH</span></pre>

<p>
	ستشاهد GOPATH/bin$ الذي سيظهر في مجلد home، فإذا سجلت الدخول على أساس مستخدِم عادي وليكن sammy، فسترى ‎/Users/sammy/go/bin في المسار:
</p>

<pre class="ipsCode">/Users/sammy/go/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
</pre>

<p>
	الآن بعد أن أنشأت المجلد الجذر لمساحة العمل وضبطت مجموعة متغيرات البيئة <code>GOPATH$</code> الخاصة بك، أصبح بإمكانك إنشاء مشاريعك باستخدام بنية المجلد التالية، كما يفترض هذا المثال أنك تستخدِم موقع Github لاستضافة مشروعك:
</p>

<pre class="ipsCode">$GOPATH/src/github.com/username/project
</pre>

<p>
	إذا كنت تعمل على مشروع <a href="https://github.com/digitalocean/godo" ipsnoembed="false" rel="external nofollow">https://github.com/digitalocean/godo</a> مثلًا، فستخزنه في المجلد التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_85" 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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_87" style=""><span class="pln">go get github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	يمكنك أيضًا التحقق من نجاح عملية التحميل من خلال عرض محتويات المجلد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_89" style=""><span class="pln">ls </span><span class="pun">-</span><span class="pln">l $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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	يجب أن تشاهد خرجًا يشبه الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_91" style=""><span class="typ">Output</span><span class="pln">
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">2892</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> CHANGELOG</span><span class="pun">.</span><span class="pln">md
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">1851</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> CONTRIBUTING</span><span class="pun">.</span><span class="pln">md
</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">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">4893</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> vpcs</span><span class="pun">.</span><span class="pln">go
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> sammy  staff   </span><span class="lit">4091</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">56</span><span class="pln"> vpcs_test</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	بذلك تكون أنشأت مساحة عمل خاصة بك وضبطت متغيرات البيئة اللازمة، وفي الخطوة التالية سنختبر مساحة العمل هذه من خلال كتابة شيفرة برنامج بسيط.
</p>

<h2>
	الخطوة 6 - إنشاء برنامج بسيط
</h2>

<p>
	ستنشئ برنامج "Hello, World!‎" بغية اختبار مساحة العمل والتعرف أكثر على جو، إذ ستنشئ هنا ملفًا مصدريًا واحد لجو وليس مشروعًا متكاملًا، لذا لا داعي لأن تكون ضمن مساحة العمل الخاصة بك لإنجاز ذلك.
</p>

<p>
	افتح محرر نصوص سطر الأوامر nano من المجلد الرئيسي وأنشئ ملفًا جديدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_93" style=""><span class="pln">$ nano hello</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	اكتب برنامجك في الملف الجديد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_95" 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">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستستخدِم هذه الشيفرة حزمة fmt وستستدعي الدالة <code>Println</code> لطباعة عبارة Hello, World!‎ التي مُرِّرت إلى الدالة.
</p>

<p>
	اخرج الآن من المحرر nano بالضغط على مفتاحي CTRL+ x وعند مطالبتك بحفظ الملف اضغط على y ثم ENTER، وبمجرد الخروج من nano والعودة إلى الصدَفة شغّل برنامج hello.go الذي أنشأته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_97" style=""><span class="pln">go run hello</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1282_99" style=""><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!</span></pre>

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

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

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

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-go-and-set-up-a-local-programming-environment-on-macos" rel="external nofollow">How To Install Go and Set Up a Local Programming Environment on macOS</a> لصاحبه Gopher Guides.
</p>

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

<ul>
	<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="">تثبيت لغة جو وإعداد بيئة برمجة محلية على أبونتو</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/%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>
</ul>
]]></description><guid isPermaLink="false">1767</guid><pubDate>Mon, 14 Nov 2022 16:04:00 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x644;&#x63A;&#x629; &#x62C;&#x648; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x628;&#x64A;&#x626;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62D;&#x644;&#x64A;&#x629; &#x639;&#x644;&#x649; &#x623;&#x628;&#x648;&#x646;&#x62A;&#x648;</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6365ee3f981e6_1----Go-------Ubuntu(1).png.39760be6e2762daf3608a2deaa46a38b.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="">جو Go</a> لغة برمجة حديثة ذات قواعد syntax عالية المستوى على غرار <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/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a> و<a href="https://academy.hsoub.com/programming/ruby/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%b1%d9%88%d8%a8%d9%8a-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d9%8a%d8%a9-r244/" rel="">روبي</a> و<a href="https://academy.hsoub.com/programming/javascript/%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-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافاسكربت</a>، وقد طوّرتها شركة جوجل Google في عام 2007 لتكون ملائمةً لنوعية احتياجات جوجل الحسابية من حيث التصريف compilation السريع وسهولة البرمجة والتنفيذ الفعّال.
</p>

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

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

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

<p>
	حاسوب -أو آلة افتراضية- مثبت عليه نظام أبونتو 20.04 مع إمكانية وصول إدارية والاتصال <a href="https://academy.hsoub.com/devops/networking/%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r571/" rel="">بالانترنت</a>.
</p>

<h2>
	الخطوة 1- إعداد جو
</h2>

<p>
	الخطوة الأولى هي تثبيت جو عن طريق تحميل الإصدار الحالي من جو من الصفحة الرسمية، لذا يجب أن تحصل على <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> لآخر نسخة من ملف Tarball (أو tarfile؛ اسم المجموعة أو أرشيف الملفات المُصرّفة معًا باستخدام الأمر tar)، كما يجب عليك الانتباه إلى قيمة SHA256 المدرَجة بجوارها لأنك ستحتاجها للتحقق من الملف الذي حُمِّل. في وقت كتابة هذه المقالة كان أحدث إصدار <code>go1.16.7</code>.
</p>

<p>
	سننجز عملية التثبيت من خلال <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="">سطر الأوامر command line</a> -ومعروف أيضًا باسم الصدفة shell أو الطرفية Terminal وهو وسيلة تخاطب مع الحاسوب عبر كتابة الأوامر له- الذي يُمكّنك من تعديل وأتمتة العديد من المهام التي تؤديها على جهاز الحاسوب كل يوم، وهو أداة أساسية لمطورِي البرامج.
</p>

<p>
	يمكنك العثور على تطبيق سطر الأوامر من خلال النقر على أيقونة أبونتو في الزاوية العلوية اليسرى من شاشتك وكتابة Terminal في شريط البحث ثم انقر على أيقونة تطبيق الطرفية لفتحه أو يمكنك الضغط على مفاتيح CTRL + ALT + T على لوحة المفاتيح في الوقت نفسه لفتح تطبيق الطرفية تلقائيًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111469" href="https://academy.hsoub.com/uploads/monthly_2022_11/UbuntuSetUp.png.83c1495042001a4328874a1e24ca6259.png" rel=""><img alt="فتح تطبيق الطرفية " class="ipsImage ipsImage_thumbnailed" data-fileid="111469" data-unique="fwglkmbcw" src="https://academy.hsoub.com/uploads/monthly_2022_11/UbuntuSetUp.png.83c1495042001a4328874a1e24ca6259.png" style="width: 600px; height: auto;"></a>
</p>

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

<p>
	تأكد من أنك في المجلد home (~) قبل بدء تحميل جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_6" style="">
<span class="pln">$ cd </span><span class="pun">~</span></pre>

<p>
	استخدم الأمر <code>curl</code> للحصول على عنوان URL الخاص بالملف tarball الذي نسخته من الصفحة الرسمية لجو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_8" style="">
<span class="pln">$ curl </span><span class="pun">-</span><span class="pln">OL https</span><span class="pun">:</span><span class="com">//golang.org/dl/go1.16.7.linux-amd64.tar.gz</span></pre>

<p>
	استخدم التجزئة <code>sha256sum</code> للتحقق من صلاحية ملف tarball:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_10" style="">
<span class="pln">$ sha256sum go1</span><span class="pun">.</span><span class="lit">16.7</span><span class="pun">.</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">amd64</span><span class="pun">.</span><span class="pln">tar</span><span class="pun">.</span><span class="pln">gz</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_14" style="">
<span class="pln">go1</span><span class="pun">.</span><span class="lit">16.7</span><span class="pun">.</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">amd64</span><span class="pun">.</span><span class="pln">tar</span><span class="pun">.</span><span class="pln">gz
</span><span class="lit">7fe7a73f55ba3e2285da36f8b085e5c0159e9564ef5f63ee0ed6b818ade8ef04</span><span class="pln">  go1</span><span class="pun">.</span><span class="lit">16.7</span><span class="pun">.</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">amd64</span><span class="pun">.</span><span class="pln">tar</span><span class="pun">.</span><span class="pln">gz</span></pre>

<p>
	استخرِج بعد ذلك الأرشيف الذي حمِّل وثبّته في الموقع المطلوب على النظام، ويوصى في المسار usr/local/. يتضمن هذا الأمر الراية <code>C-</code> التي ترشد tar إلى المجلد المحدد قبل تنفيذ أي عمليات أخرى.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_17" style="">
<span class="pln">$ sudo tar </span><span class="pun">-</span><span class="pln">C </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local </span><span class="pun">-</span><span class="pln">xvf go1</span><span class="pun">.</span><span class="lit">16.7</span><span class="pun">.</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">amd64</span><span class="pun">.</span><span class="pln">tar</span><span class="pun">.</span><span class="pln">gz</span></pre>

<p>
	أصبح لديك الآن مجلدًا باسم go في المسار usr/local/، وبذلك تكون قد حمّلت وثبّت جو على نظام أبونتو الخاص بك.
</p>

<h2>
	الخطوة 2 - إنشاء مساحة العمل Workspace الخاصة بك
</h2>

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

<ul>
<li>
		src: مجلد ستوضع فيه ملفات جو المصدرية، وهي الملفات التي تُكتب وتُنشأ باستخدام لغة جو، إذ سيستخدِمها مُصرِّف جو لإنشاء ملفات قابلة للتنفيذ أي ملفات ثنائية يمكن تشغيلها على نظامك لتنفيذ المهام التي تتضمنها.
	</li>
	<li>
		bin: مجلد ستوضع فيه الملفات الثنائية التي أنشِئت وثُبِّتت بواسطة أدوات جو؛ بعبارة أخرى هي البرامج التي صُرِّفت من التعليمات البرمجية المصدرية الخاصة بك أو غيرها من التعليمات البرمجية المصدرية المرتبطة بجو والتي حمّلتها.
	</li>
</ul>
<p>
	من المحتمل أن يحتوي المجلد src على عدة مستودعات للتحكم في الإصدارات مثل Git و Mercurial و Bazaar، إذ سيسمح لك هذا باستيراد أساسي canonical import للشيفرة البرمجية في مشروعك، والاستيراد الأساسي هو عملية استيراد تشير إلى حزمة مؤهلة وجاهزة بالكامل مثل github.com/digitalocean/godo.
</p>

<p>
	سترى مجلدات مثل github.com أو golang.org أو غيرها عندما يستورد برنامجك مكتبات تابعة لجهات خارجية، فإذا كنت تستخدِم -أو لديك- شيفرات برمجية على إحدى المواقع مثل github.com، فستضع أيضًا هذه المشاريع أو ملفات المصدر ضمن هذا المجلد وستتعرّف على ذلك بعد قليل.
</p>

<p>
	تبدو مساحة العمل النموذجية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_19" 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"> buffalo                                      </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> dlv                                          </span><span class="com"># أمر تنفيذي</span><span class="pln">
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> packr                                        </span><span class="com"># أمر تنفيذي</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"> digitalocean
            </span><span class="pun">└──</span><span class="pln"> godo
                </span><span class="pun">├──</span><span class="pln"> </span><span class="pun">.</span><span class="pln">git                            </span><span class="com"># البيانات الوصفية لمستودع جيت</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account</span><span class="pun">.</span><span class="pln">go                      </span><span class="com"># ملف الحزمة</span><span class="pln">
                </span><span class="pun">├──</span><span class="pln"> account_test</span><span class="pun">.</span><span class="pln">go             </span><span class="com"># اختبار ملف الحزمة</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"> timestamp</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">├──</span><span class="pln"> timestamp_test</span><span class="pun">.</span><span class="pln">go
                </span><span class="pun">└──</span><span class="pln"> util
                    </span><span class="pun">├──</span><span class="pln"> droplet</span><span class="pun">.</span><span class="pln">go
                    </span><span class="pun">└──</span><span class="pln"> droplet_test</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	يُعَدّ المجلد الافتراضي لمساحة العمل في جو بدءًأ من الإصدار 1.8 هو المجلد الرئيسي home للمستخدِم الذي يحتوي على مجلد فرعي باسم go أي HOME/go$، فإذا استخدَمت إصدارًا أقدم من 1.8، فمن الأفضل الاستمرار في استخدام الموقع HOME/go$ لمساحة عملك.
</p>

<p>
	نفّذ الأمر التالي لإنشاء بنية مجلد لمساحة العمل الخاصة بك في جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_21" style="">
<span class="pln">$ mkdir </span><span class="pun">-</span><span class="pln">p $HOME</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/{</span><span class="pln">bin</span><span class="pun">,</span><span class="pln">src</span><span class="pun">}</span></pre>

<p>
	يطلب الخيار <code>p-</code> من mkdir إنشاء جميع العناصر الرئيسية parents في المجلد حتى لو لم تكن موجودة حاليًا، إذ يؤدي استخدام <code>{bin، src}</code> إلى إنشاء مجموعة من الوسائط لـ <code>mkdir</code> وإخباره بإنشاء كل من مجلد bin و src.
</p>

<p>
	سيؤدي ذلك إلى إنشاء بنية المجلد التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_23" style="">
<span class="pun">└──</span><span class="pln"> $HOME
    </span><span class="pun">└──</span><span class="pln"> go
        </span><span class="pun">├──</span><span class="pln"> bin
        </span><span class="pun">└──</span><span class="pln"> src</span></pre>

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

<p>
	يمكن ضبط المتغير <code>GOPATH$</code> الخاص بك من خلال إضافة المتغيرات العامة إلى ‎~/.profile‎‎ وربما تحتاج أيضًا إلى إضافته إلى ملف zshrc. أو bashrc. تبعًا لتهيئة الصدَفة shell الخاصة بك.
</p>

<p>
	أولًا، افتح ‎~/.profile‎‎ باستخدام nano أو محرر النصوص المفضل لديك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_25" style="">
<span class="pln">$ nano </span><span class="pun">~/.</span><span class="pln">profile</span></pre>

<p>
	حدِّد المتغير <code>GOPATH$</code> الخاص بك من خلال إضافة ما يلي إلى الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_27" style="">
<span class="kwd">export</span><span class="pln"> GOPATH</span><span class="pun">=</span><span class="pln">$HOME</span><span class="pun">/</span><span class="pln">go</span></pre>

<p>
	عندما يُصرّف جو الأدوات ويثبّتها، فسيضعها في المجلد GOPATH/bin$، ومن الشائع إضافة المجلد الفرعي bin/ الخاص بمساحة العمل إلى <code>PATH</code> في ‎~/.profileكما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_29" style="">
<span class="kwd">export</span><span class="pln"> PATH</span><span class="pun">=</span><span class="pln">$PATH</span><span class="pun">:</span><span class="pln">$GOPATH</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	سيسمح لك ذلك بتشغيل أيّ برامج مُصرَّفة بواسطة جو أو محمّلة عبر أدوات جو من أيّ مكان على نظامك.
</p>

<p>
	أخيرًا، ستحتاج إلى إضافة المجلد bin إلى المسار PATH من خلال إضافة المسار usr/local/go/bin/ في نهاية السطر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_32" style="">
<span class="kwd">export</span><span class="pln"> PATH</span><span class="pun">=</span><span class="pln">$PATH</span><span class="pun">:</span><span class="pln">$GOPATH</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	أصبح بإمكانك الآن الوصول إلى جميع أدوات جو من أيّ مكان على نظامك.
</p>

<p>
	نفّذ الأمر التالي لتحميل المتغيرات العامة وتحديث الصدَفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7870_72" style="">
<span class="pun">.</span><span class="pln"> </span><span class="pun">~/.</span><span class="pln">profile</span></pre>

<p>
	يمكنك التحقق من تحديث المتغير <code>PATH$</code> باستخدام الأمر <code>echo</code> وقراءة الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_34" style="">
<span class="pln">$ echo $PATH</span></pre>

<p>
	ستشاهد GOPATH/bin$ الخاص بك والذي سيظهر في مجلد home، فإذا سجّلت الدخول على أساس جذر، فسترى root/go/bin/ في المسار.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_36" style="">
<span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">games</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">games</span><span class="pun">:/</span><span class="pln">snap</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">root</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	ستشاهد أيضًا المسار الخاص بأدوات جو ضمن المجلد usr/local/go/bin/:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_38" style="">
<span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">sbin</span><span class="pun">:/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">games</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">games</span><span class="pun">:/</span><span class="pln">snap</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">root</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">:/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">local</span><span class="pun">/</span><span class="pln">go</span><span class="pun">/</span><span class="pln">bin</span></pre>

<p>
	تحقق الآن من التثبيت عن طريق التحقق من الإصدار الحالي من جو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_40" style="">
<span class="pln">$ go version</span></pre>

<p>
	سيظهر لك خرج يشبه التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_43" style="">
<span class="pln">go version go1</span><span class="pun">.</span><span class="lit">12.1</span><span class="pln"> linux</span><span class="pun">/</span><span class="pln">amd64</span></pre>

<p>
	الآن بعد أن أنشأتَ المجلد الجذر لمساحة العمل وضبطت مجموعة متغيرات البيئة <code>GOPATH$</code> الخاصة بك، أصبح بإمكانك إنشاء مشاريعك باستخدام بنية المجلد التالية، وسيفترض هذا المثال أنك تستخدِم موقع github.com لاستضافة مشروعك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_45" 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">username</span><span class="pun">/</span><span class="pln">project</span></pre>

<p>
	إذا كنت تعمل على مشروع <a href="https://github.com/digitalocean/godo" ipsnoembed="false" rel="external nofollow">https://github.com/digitalocean/godo</a> على سبيل المثال، فسيُخزَّن في المجلد التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_47" 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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_52" style="">
<span class="pln">$ go get github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	سيؤدي ذلك إلى تحميل محتويات مكتبة godo وإنشاء المجلد GOPATH/src/github.com/digitalocean/godo$ على جهازك.
</p>

<p>
	يمكنك أيضًا التحقق من نجاح عملية تحميل حزمة godo من خلال سرد محتويات المجلد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_54" style="">
<span class="pln">$ ll $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">digitalocean</span><span class="pun">/</span><span class="pln">godo</span></pre>

<p>
	يجب أن تشاهد خرجًا يشبه الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_56" style="">
<span class="pln">drwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">4</span><span class="pln"> root root  </span><span class="lit">4096</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> </span><span class="pun">./</span><span class="pln">
drwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">3</span><span class="pln"> root root  </span><span class="lit">4096</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> </span><span class="pun">../</span><span class="pln">
drwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">8</span><span class="pln"> root root  </span><span class="lit">4096</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> </span><span class="pun">.</span><span class="pln">git</span><span class="pun">/</span><span class="pln">
</span><span class="pun">-</span><span class="pln">rwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">1</span><span class="pln"> root root     </span><span class="lit">8</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> </span><span class="pun">.</span><span class="pln">gitignore</span><span class="pun">*</span><span class="pln">
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> root root    </span><span class="lit">61</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> </span><span class="pun">.</span><span class="pln">travis</span><span class="pun">.</span><span class="pln">yml
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> root root  </span><span class="lit">2808</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> CHANGELOG</span><span class="pun">.</span><span class="pln">md
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> root root  </span><span class="lit">1851</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> CONTRIBUTING</span><span class="pun">.</span><span class="pln">md
</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">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> root root  </span><span class="lit">4893</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> vpcs</span><span class="pun">.</span><span class="pln">go
</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">--</span><span class="pln">r</span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> root root  </span><span class="lit">4091</span><span class="pln"> </span><span class="typ">Apr</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> vpcs_test</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<h2>
	الخطوة 3 - إنشاء برنامج بسيط في جو
</h2>

<p>
	ستنشئ برنامج “Hello, World!” بغية اختبار مساحة العمل والتعرف أكثر على جو. ستنشئ هنا ملف مصدري واحد لجو وليس مشروعًا فعليًا، لذا لا داعي لأن تكون ضمن مساحة العمل الخاصة بك لإنجاز ذلك.
</p>

<p>
	افتح محرر نصوص سطر الأوامر nano من المجلد الرئيسي وأنشئ ملفًا جديدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_58" style="">
<span class="pln">$ nano hello</span><span class="pun">.</span><span class="pln">go</span></pre>

<p>
	اكتب برنامجك في الملف الجديد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_60" 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">"Hello, World!"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستستخدِم هذه الشيفرة حزمة fmt وستستدعي الدالة <code>Println</code> لطباعة Hello, World!‎ التي تم مرِّرت على أساس وسيط إلى الدالة.
</p>

<p>
	اخرج الآن من المحرر nano بالضغط على مفتاحَي CTRL+ X، وعند مطالبتك بحفظ الملف، اضغط على <code>Y</code> ثم <code>ENTER</code>.
</p>

<p>
	شغِّل برنامج hello.go الذي أنشأته عند الخروج من nano والعودة إلى الصدَفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_63" style="">
<span class="pln">go run hello</span><span class="pun">.</span><span class="pln">go</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9902_65" style="">
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!</span></pre>

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

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

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

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-go-on-ubuntu-20-04" rel="external nofollow">How To Install Go on Ubuntu 20.04</a> لصاحبه Gopher Guides.
</p>

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

<ul>
<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/%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>
</ul>
]]></description><guid isPermaLink="false">1766</guid><pubDate>Sat, 05 Nov 2022 05:50:34 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x631;&#x648;&#x633; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x641;&#x627;&#x62F;&#x629; &#x645;&#x646; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x628;&#x644;&#x63A;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_05/Lessons-learned-from-programming-in-Go.jpg.1fdfdadbf6ec63f3bed6b154faa0db5d.jpg" /></p>

<p>
	تعلم كيفية حلّ المشاكل الشائعة في أنظمة المعالجة المتزامنة وتفادى صداع المرافق لحلّها في المستقبل.
</p>

<p>
	عند التعامل مع أنظمة موزعة ومعقدة، فمن الوارد جدًا أن تحتاج للمعالجة المتزامنة. ولكن لن يكون بناء شبكة عالمية خاصة توجه الحزم ديناميكيًا بدقة تصلّ للملّي ثانية أمرًا ممكنًا بدون نظام شديد التزامن. يعتمد هذا التوجيه الديناميكي على حالة الشبكة، وبينما توجد العديد من المعاملات الّتي يجب مراعاتها في هذا الأمر، سينصبُ تركيزنا على مقاييس <a href="https://en.wikipedia.org/wiki/Metrics_%D9%AA28networking%D9%AA29" rel="external nofollow">الارتباط</a>. في سياق الحالة الّتي سنناقشها، يمكن أن تكون مقاييس الارتباط أي شيء متعلق بالحالة رابط الشبكة و خصائصه (مثل: زمن تأخير الارتباط).
</p>

<h2>
	الفحص المتزامن لمقاييس الارتباط
</h2>

<p>
	تعتمد خوارزمية <a href="https://people.ece.cornell.edu/atang/pub/15/HALO_ToN.pdf" rel="external nofollow">HALO</a> (وهي اختصارًا Hop-by-Hop Adaptive Link-State Optimal Routing) على التوجيه الديناميكي جزئيًا على مقاييس الارتباط لحساب جدول التوجيه الخاص بها. تُجمعُ هذه المقاييس من خلال مكون مستقل متواجد بكلّ <a href="https://en.wikipedia.org/wiki/Point_of_presence" rel="external nofollow">PoP</a> (نقطة مشاركة). أما نقاط المشاركة (PoPs) وهي آلات تمثل كيانًا موجهًا واحدًا في شبكاتنا، ومتصلة بارتباطات متعددة وتنتشر في مواقع كثيرة مشكلةً بذلك شبكتنا. يستكشف هذا المكون الأجهزة المجاورة باستخدام حزم الشبكة، وسيُردُ هؤلاء الجيران بجواب أولي. يمكن استخلاص قيم زمن تأخير الارتباط من الأجوبة المتلقاة من هذه النقاط. نظرًا لأن لكل نقطة اتصال أكثر من جار واحد، فإن طبيعة هذه المهمة متزامنة جوهريًا: نحتاج إلى قياس وقت الاستجابة لكل رابط مجاور في الوقت الفعلي. لا يمكننا تحمل المعالجة التسلسلية ويجب معالجة كلّ جواب بأقرب وقت ممكن لحساب مقياس الارتباط.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/1.png.fc1f53f90ef69e62e7858aae7040241c.png" data-fileid="44750" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44750" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/1.png.fc1f53f90ef69e62e7858aae7040241c.png" alt="1.png"></a>
</p>

<h2>
	أرقام التسلسل وإعادة الضبط: حالة إعادة الترتيب
</h2>

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

<h2>
	عملية تأسيس اتصال UDP وحالات الآلة المحدودة
</h2>

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

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/2.png.addf8b0be8eea0576b735962501f24fd.png" data-fileid="44751" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44751" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/2.thumb.png.9e941d7b20fa2767ba0190b3d07bff0c.png" alt="2.png"></a>
</p>

<p>
	تُنشأ مُعرّفات الجلسة من خلال مؤسس الاتصالات. ويكون التسلسل الكامل لعملية الإنشاء على الشكل التالي:
</p>

<ol>
<li>
		يرسل المرسل حزمة <strong>SYN(ID)‎</strong>.
	</li>
	<li>
		يخزن المُستقبل المُعرّف الواصل له (وهو <strong>ID</strong>) ويرسل <strong>SYN-ACK (ID)‎</strong>.
	</li>
	<li>
		يتلقى المرسل <strong>SYN-ACK (ID)‎</strong> ويرسل <strong>ACK (ID)‎</strong>. كما يبدأ أيضًا في إرسال الحزم الّتي تبدأ بالتسلسل رقم 0.
	</li>
	<li>
		يتحقق المرسل من آخر معرّف <strong>ID</strong> استلمه، ويقبل <strong>ACK (ID)‎</strong> إذا كان معرّفه مطابقًا للمعرّف (<strong>ID</strong>) السابق. كما يبدأ بقبول الحزم الّتي تبدأ برقم تسلسلي 0.
	</li>
</ol>
<h2>
	معالجة المُهلة الزمنية للحالة
</h2>

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

<ul>
<li>
		أحداث الارتباط: وهي تحديث لحالة الارتباط فإما عملية ارتباط أو عملية فصل الارتباط. يمكن لهذا إما بدء جلسة اتصال أو إنهاء جلسة موجودة.
	</li>
	<li>
		أحداث تراسل الحزم: وهي لحزم التحكم مثل: <strong>(SYN/SYN-ACK/ACK)</strong> أو استقصاء الاستجابات فقط.
	</li>
	<li>
		أحداث انتهاء المُهلة: هي الأحداث الّتي تُشغّل بعد انتهاء المهلة المُجدولة لحالة الجلسة الحالية.
	</li>
</ul>
<p>
	يكمن التحدي الرئيسي الّذي نواجهه هنا هو كيفية التعامل مع انتهاء زمن المُهلة المتزامنة والأحداث الأخرى بنفس الوقت. وهنا يمكن للمرء أن يسقط بسهولة في مشاكلة القفل المستعصي (Deadlocks) ومشكلة السباق (Race conditions).
</p>

<h2>
	النهج الأول
</h2>

<p>
	سنستخدم في هذا المشروع لغة <a href="https://golang.org/" rel="external nofollow">Golang</a> لإنها توفر آليات مزامنة أصيلة مثل: القنوات والأقفال الأصيلة وهي قادرة أيضًا على تدوير الخيوط (Threads) الخفيفة لمعالجتهم بطريقة متزامنة (لمزيد من المعلومات يمكنك الاطلاع على مقال سابق أخذنا فيه نظرة سريعة على لغة Golang).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/3.png.d8a087ede077b6237cc3ce9f56df34a8.png" data-fileid="44752" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44752" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/3.png.d8a087ede077b6237cc3ce9f56df34a8.png" alt="3.png"></a>
</p>

<p>
	سنبدأ أولًا بتصميم هيكلًا (Struct) لتمثيل مُعالجات جلسات العمل والمُهلة.
</p>

<pre class="ipsCode" id="ips_uid_2336_7">
type  Session  struct  {    
  State SessionState    
  Id SessionId    
  RemoteIp  string    
}  

type  TimeoutHandler  struct  {    
  callback  func(Session)    
  session Session    
  duration  int    
  timer  *timer.Timer    
}
</pre>

<p>
	تُحددُ (Session) جلسة الاتصال بمعرّف الجلسة (ID)، وعنوان IP للارتباط المجاور (RemoteIp)، وحالة الجلسة الحالية (State).
</p>

<p>
	كما يحدد معالج المُهلة (TimeoutHandler) بدالّة رد النداء (callback)، والجلسة الّتي يجب أن يعمل من أجلها (session)، والمدة (duration)، ومؤشر للوقت المُجدول (timer).
</p>

<p>
	ستُخزن خارطة (أو خريطة) عامة (Global Map) -الخرائط Maps في لغة Go هي مصفوفات ترابطية يمكن التعديل عليها ديناميكيًا وهي تشبه نوع القاموس او الهاش في اللغات البرمجية الأخرى- مُعالج المُهلة المُجدولة لكل جلسة ارتباط مجاورة.
</p>

<pre class="ipsCode">
SessionTimeout map[Session]*TimeoutHandler
</pre>

<p>
	تُسجّل مُهلةٌ ما وتُلغى بالدوالّ التالية:
</p>

<pre class="ipsCode">
// الدالّة المسؤولة عن جدولة المهلة لرد النداء
func (timeout* TimeoutHandler) Register() {  
  timeout.timer = time.AfterFunc(time.Duration(timeout.duration) * time.Second, func() {  
    timeout.callback(timeout.session)  
  })  
}

func (timeout* TimeoutHandler) Cancel() {  
  if timeout.timer == nil {  
    return  
  }  
  timeout.timer.Stop()  
}
</pre>

<p>
	لإنشاء المُهل وتخزينها، يمكنك استخدام دالّة مشابه لهذه:
</p>

<pre class="ipsCode">
func CreateTimeoutHandler(callback func(Session), session Session, duration int) *TimeoutHandler {  
  if sessionTimeout[session] == nil {  
    sessionTimeout[session] := new(TimeoutHandler)  
  }  

  timeout = sessionTimeout[session]  
  timeout.session = session  
  timeout.callback = callback  
  timeout.duration = duration  
  return timeout  
}
</pre>

<p>
	بمجرد إنشاء معالج المُهلة وتسجيله بنجاح، سيُشغل عندها رد النداء بعد انقضاء المدة الزمنية (duration) المقدرة بالثانية. بينما بعض الأحداث الأخرى ستتطلبُ منك إعادة جدولة معالج المُهلة (كما يحدث في حالة <strong>SYN</strong> - كلّ 3 ثوان).
</p>

<p>
	لذلك، يمكنك إعادة جدولة المُهلة لرد نداء معين. هكذا:
</p>

<pre class="ipsCode">
func synCallback(session Session) {  
  sendSynPacket(session)

  // reschedules the same callback.  
  newTimeout := NewTimeoutHandler(synCallback, session, SYN_TIMEOUT_DURATION)  
  newTimeout.Register()

  sessionTimeout[state] = newTimeout  
}
</pre>

<p>
	سيعيد رد النداء جدولة نفسه في معالج مهلة جديد ويحدّث الخارطة العامة بقيمة <strong>sessionTimeout</strong> الجديدة.
</p>

<h2>
	سباق البيانات والمراجع
</h2>

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

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

<ol>
<li>
		لديك معالج (handler) مجدول بمُهلة معينة.
	</li>
	<li>
		الخيط 1 (Thread 1):<br>
		أ) تتلقى حزمة تحكم، وتريد الآن إلغاء المُهلة المسجلة والانتقال لحالة الجلسة التالية. (مثلًا، أن تتلقى <strong>SYN-ACK</strong> بعد إرسال ** SYN **).<br>
		ب) يمكنك استدعاء الدالّة <strong><em>timeout.Cancel()‎</em></strong>، والّتي بدورها ستستدعي الدالّة <strong><em>timer.Stop()‎</em></strong>. (لاحظ أن توقف مؤقت لغة Golang لن يمنع تشغيل المؤقت الّذي انتهت مدته الزمنية بالفعل).
	</li>
	<li>
		الخيط 2:<br>
		أ) قبل استدعاء دالة الإلغاء مباشرةً، انقضت المدة الزمنية للمؤقت، وكان رد النداء على وشك التنفيذ.<br>
		ب) نفذَّ رد النداء، وسجُلّت المُهلة الجديدة وحُدّثت أيضًا الخارطة العامة.
	</li>
	<li>
		الخيط 1:<br>
		أ) الانتقال لحالة الجلسة الجديدة وتسجيل مُهلة جديدة، وتحديث الخارطة العامة.
	</li>
</ol>
<p>
	كلا الخيطين حدثا الخارطة العامة بالمُهلة الجديدة تحديثًا متزامنًا. والنتيجة النهائية هي أنك فشلتَ في إلغاء المُهلة المسجلة، وفقدتَ أيضًا الإشارة للمُهلة المُعادُ جدولتها والّتي نفذّت بواسطة الخيط 2. وبذلك سيستمر المعالج في التنفيذ وإعادة الجدولة لفترى من الزمن، مما سيؤدي لسلوك غير مرغوب به في البرنامج.
</p>

<h2>
	هل يعد استخدام القفل كافيًا لحل المشكلة؟
</h2>

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

<pre class="ipsCode">
func (timeout* TimeoutHandler) Register() {  
  timeout.timer = time.AfterFunc(time.Duration(timeout.duration) * time._Second_, func() {  
    stateLock.Lock()  
    defer stateLock.Unlock()

    timeout.callback(timeout.session)  
  })  
}
</pre>

<p>
	إن الفرق الآن هو أن التحديثات على الخارطة العامة متزامنة، ولكن هذا لا يمنع رد النداء من العمل بعد استدعاء الدالّة <strong>timeout.Cancel()‎</strong> - وتحدث هذه الحالة إذا انتهت المدة الزمنية للمؤقت المُجدول ولكنه لم يجلب القفل بعد. عندها يجب أن تُفقدُ مرة أخرى الإشارة لأحد المُهل المسجلة.
</p>

<h2>
	استخدام قنوات الإلغاء
</h2>

<p>
	بدلًا من الاعتماد على الدالّة <strong>timer.Stop()‎</strong> في لغة Golang، الّذي لن يمنع رد النداء المنتهية مُهلته الزمنية من التنفيذ، سنعتمد على قنوات الإلغاء.
</p>

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

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

<pre class="ipsCode">
func (timeout *TimeoutHandler) Register() chan struct{} {  
  cancelChan := make(chan struct{})  

  go func () {  
    select {  
    case _ = &lt;- cancelChan:  
      return  
    case _ = &lt;- time.AfterFunc(time.Duration(timeout.duration) * time.Second):  
      func () {  
        stateLock.Lock()  
        defer stateLock.Unlock()

        timeout.callback(timeout.session)  
      } ()  
    }  
  } ()

  return cancelChan  
}

func (timeout* TimeoutHandler) Cancel() {  
  if timeout.cancelChan == nil {  
    return  
  }  
  timeout.cancelChan &lt;- struct{}{}  
}
</pre>

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

<p>
	الحل في هذه الحالة هو التحقق من قناة الإلغاء بداخل نطاق المُهلة بعد جلب القفل.
</p>

<pre class="ipsCode">
  case _ = &lt;- time.AfterFunc(time.Duration(timeout.duration) * time.Second):  
    func () {  
      stateLock.Lock()  
      defer stateLock.Unlock()  

      select {  
      case _ = &lt;- handler.cancelChan:  
        return  
      default:  
        timeout.callback(timeout.session)  
      }  
    } ()  
  }
</pre>

<p>
	أخيرًا، هذا سيضمنُ أن يُنفذّ رد النداء فقط بعد جلب القفل وقبل تفعيل الإلغاء.
</p>

<h2>
	احذر من مشكلة القفل المستعصي
</h2>

<p>
	يبدو أن هذا الحل يعمل عملًا جيدًا. إلا أنه بالرغم من ذلك نلاحظ وجود مشكلة <a href="https://en.wikipedia.org/wiki/Deadlock" rel="external nofollow">القفل المستعصي</a> المخفية.
</p>

<p>
	حاول أن تعيد قراءة الشيفرة البرمجية أعلاه وأن تحاول العثور عليها بنفسك. فكر في الاستدعاءات المتزامنة للدوالّ الموضحة.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_05/4.jpg.c82171c3f1980767d35955f9eac78a9c.jpg" data-fileid="44753" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="44753" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_05/4.jpg.c82171c3f1980767d35955f9eac78a9c.jpg" alt="4.jpg"></a>
</p>

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

<pre class="ipsCode">
func (timeout* TimeoutHandler) Cancel() {  
  if timeout.cancelChan == nil {  
    return  
  }  

  select {  
  case timeout.cancelChan &lt;- struct{}{}:  
  default:  
    // can’t send on the channel, someone has already requested the cancellation.  
  }  
}
</pre>

<h2>
	الخلاصة
</h2>

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

<h3>
	تحديث البيانات المشتركة بدون مزامنة
</h3>

<p>
	يبدو هذا الأمر جليًا، ولكن من الصعب تحديد ما إذا كانت التحديثات المتزامنة تحدث في مواقع مختلفة. والنتيجة هي حالة السباق على البيانات، حيث يمكن أن تؤدي التحديثات المتعددة لنفس البيانات لفقدان التحديث، بسبب تجاوز أحد التحديثات لتحديث آخر. في مثالنا، حدثنا مرجع المُهلة المُجدولة على نفس الخارطة المشتركة (Shared Map). (من المثير للاهتمام أنه إذا اكتشفت لغة Go عملية قراءة/كتابة متزامنة على نفس كائن الخارطة، فسترمي خطأ مُميت - يمكنك تشغيل <a href="https://golang.org/doc/articles/race_detector.html" rel="external nofollow">مثال حي لكاشف سباق البيانات</a>). يؤدي هذا في النهاية إلى فقدان مرجع المُهلة، ويجعل من المستحيل إلغاء المُهلة المحددة. تذكر دائمًا استخدام الأقفال عند الحاجة إليها.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="44754" data-unique="z2oc4t26g" src="https://academy.hsoub.com/uploads/monthly_2020_05/5.jpeg.d6cce45f5a3ebcccb9799267bc140ff7.jpeg" alt="5.jpeg"></p>

<h3>
	فقدان عمليات التحقق من الحالة
</h3>

<p>
	يلزم التحقق من الحالة في المواقف الّتي لا يمكنك فيها الاعتماد فقط على حصرية القفل. موقفنا مختلف قليلًا، لكن الفكرة الأساسية مشابهة تمامًا <a href="https://en.wikipedia.org/wiki/Monitor_%D9%AA28synchronization%D9%AA29#Condition_variables" rel="external nofollow">لمتغيرات الحالة</a>. تخيل موقفًا كلاسيكيًا حيث يكون لديك مُنتج واحد والعديد من المستهلكين يعملون في قائمة انتظار مشتركة. يمكن للمُنتج إضافة عنصر واحد لقائمة الانتظار وإيقاظ جميع المستهلكين. تعني عملية الاستيقاظ للمستهلكين بأن هنالك بعض البيانات المتاحة في قائمة الانتظار، ولأن قائمة الانتظار مشتركة، يجب مزامنة الوصول لها من خلال قفل. كلّ مستهلك لديه فرصة للاستيلاء على هذا القفل. ومع ذلك، لا يزال الحلّ غير كامل ومازلنا بحاجة للتحقق إن كان هناك عناصر في قائمة الانتظار. يلزم التحقق من الحالة لأنك لا تعرف حالة قائمة الانتظار في الوقت الّذي تمسك القفل فيه.
</p>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="44755" data-unique="otj717uzm" src="https://academy.hsoub.com/uploads/monthly_2020_05/6.png.d048154ef20b5b3126538ea2e696092c.png" alt="6.png"></p>

<h3>
	مشكلة القفل المستعصي
</h3>

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/article/19/12/go-common-pitfalls?utm_campaign=intrel" rel="external nofollow">Lessons learned from programming in Go</a> لكاتبه Eduardo Ferreira
</p>
]]></description><guid isPermaLink="false">884</guid><pubDate>Tue, 19 May 2020 17:13:15 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x639;&#x646; &#x627;&#x644;&#x645;&#x635;&#x641;&#x648;&#x641;&#x627;&#x62A; Arrays &#x648;&#x627;&#x644;&#x634;&#x631;&#x627;&#x626;&#x62D; Slices &#x627;&#x644;&#x62E;&#x627;&#x635;&#x629; &#x628;&#x644;&#x63A;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/An-introduction-to-Go-arrays-and-slices.jpg.0345a1c624aaa4c72a39f262d19fee71.jpg" /></p>

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

<p>
	هذا المقال جزء من سلسلة Go التي كتبها Mihalis Tsoukalos:
</p>

<ul>
<li>
		<em>الجزء 1:</em> <a href="https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D9%85%D8%B1%D9%88%D8%B1-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%A2%D9%85%D9%86%D8%A9-%D9%81%D9%8A-go-r837/" rel="">إنشاء كلمات مرور عشوائية وآمنة في Go</a>
	</li>
	<li>
		<em>الجزء 2:</em> <a href="https://academy.hsoub.com/programming/go/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/" rel=""> بناء خادم TCP متزامن في لغة البرمجة Go</a>.
	</li>
	<li>
		<em>الجزء 3:</em> <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>
<h2>
	المصفوفات Arrays
</h2>

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

<p>
	يمكنك تعريف مصفوفة Array في لغة البرمجة Go، تحت اسم anArray مثلًا والتي تُخزِّن أربعة أعداد صحيحة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2652_6" style="">
<span class="pln">anArray </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">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">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">4</span><span class="pun">}</span></pre>

<p>
	يُحدَّد حجم المصفوفة Array Size أولًا، ثم نوعها Array Type، وأخيرًا عناصرها Array Elements.
</p>

<p>
	تُساعدك الدّالة ()len في معرفة طول المصفوفة فحجم المصفوفة السابقة هو 4.
</p>

<p>
	إذا كنت على درايةٍ بلغات برمجة أخرى، فقد حاولت الوصول لجميع عناصر المصفوفة باستخدام حلقة for. ومع ذلك، كما سترى لاحقًا، أنّ الكلمة المفتاحية <em>range</em> الخاصة بلغة Go تُتيح لك الوصول لجميع عناصر المصفوفة أو الشريحة بسلاسة.
</p>

<p>
	وأخيرًا، إليك كيفية تحديد مصفوفة ذات بُعدين two dimentional array:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2652_8" style="">
<span class="pln">twoD </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">3</span><span class="pun">][</span><span class="lit">3</span><span class="pun">]</span><span class="pln">int</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">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="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="pun">{</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></pre>

<p>
	الملف المصدر <strong>arrays.go</strong> يُوضِّح كيفية استخدام مصفوفات Go، ها هو الكود الأكثر أهمية في ملف <strong>arrays.go</strong>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2652_10" 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"> len</span><span class="pun">(</span><span class="pln">twoD</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">
        k </span><span class="pun">:=</span><span class="pln"> twoD</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"> j </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">k</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">
                fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">k</span><span class="pun">[</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> </span><span class="str">" "</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">
</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"> a </span><span class="pun">:=</span><span class="pln"> range twoD </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 a </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">j</span><span class="pun">,</span><span class="pln"> </span><span class="str">" "</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">
</span><span class="pun">}</span></pre>

<p>
	يوضح هذا كيف يُمكنك المرور على عناصر المصفوفة باستخدام for loop والكلمة المُفتاحية range. توضّح باقي الكود الخاص بالملف <strong>arrays.go</strong> كيفية تمرير المصفوفة كمعامل دالّة.
</p>

<p>
	فيما يلي هو ناتج <strong>arrays.go</strong>:
</p>

<pre class="ipsCode">
$ go run arrays.go
Before change(): [-1 2 0 -4]
After change(): [-1 2 0 -4]
1 2 3
6 7 8
10 11 12
1 2 3
6 7 8
10 11 12
</pre>

<p>
	يوضح هذا الناتج أنّ التغييرات التي تُجريها على مصفوفة داخل دالة تُفقَد بعد إنتهاء الدالة.
</p>

<h3>
	عيوب ومساوئ المصفوفات arrays
</h3>

<p>
	لدى مصفوفات Go العديد من المساوئ التي لابد أن تأخذها بعين الإعتبار حينما تستخدمها في مشاريع Go.
</p>

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

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

<p>
	أخيرًا، يمكن أن يكون تمرير مصفوفة كبيرة إلى دالة بطيئًا جدًا، خاصة وأن Go يجب أن تنشئ نسخة من هذه المصفوفة.
</p>

<p>
	الحل لجميع هذه المشاكل هو استخدام الشرائح Slices التي توفرها Go.
</p>

<h2>
	الشرائح Slices
</h2>

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

<p>
	الشرائح لها خاصية سعة وخاصية طول، وهما ليستا نفس الشيء دائمًا. طول الشريحة هو نفس طول المصفوفة التي تحتوي على نفس عدد العناصر، ويمكن معرفتها باستخدام الدالة <code>()len</code>. أمّا سعة الشريحة فهي الغرفة التي تم تخصيصها حاليًا للشريحة، ويمكن معرفتها باستخدام الدالة <code>()cap</code>.
</p>

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

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

<p>
	يتم توضيح شرائح Go في ملف <strong>slice.go</strong>، والذي يحتوي على الكود التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2652_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">"fmt"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

func negative</span><span class="pun">(</span><span class="pln">x </span><span class="pun">[]</span><span class="pln">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"> k </span><span class="pun">:=</span><span class="pln"> range x </span><span class="pun">{</span><span class="pln">
                x</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><span class="pln">k
        </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func printSlice</span><span class="pun">(</span><span class="pln">x </span><span class="pun">[]</span><span class="pln">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"> _</span><span class="pun">,</span><span class="pln"> number </span><span class="pun">:=</span><span class="pln"> range 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">"%d "</span><span class="pun">,</span><span class="pln"> number</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">
</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">[]</span><span class="pln">int</span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</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">0</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">19</span><span class="pun">}</span><span class="pln">
        printSlice</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
        negative</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
        printSlice</span><span class="pun">(</span><span class="pln">s</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">"Before. Cap: %d, length: %d\n"</span><span class="pun">,</span><span class="pln"> cap</span><span class="pun">(</span><span class="pln">s</span><span class="pun">),</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">s</span><span class="pun">))</span><span class="pln">
        s </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">100</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">"After. Cap: %d, length: %d\n"</span><span class="pun">,</span><span class="pln"> cap</span><span class="pun">(</span><span class="pln">s</span><span class="pun">),</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">s</span><span class="pun">))</span><span class="pln">
        printSlice</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">

        anotherSlice </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">int</span><span class="pun">,</span><span class="pln"> </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">"A new slice with 4 elements: "</span><span class="pun">)</span><span class="pln">
        printSlice</span><span class="pun">(</span><span class="pln">anotherSlice</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	بالإضافة إلى ذلك، تتيح لك الدالة ()append إضافة عنصر إلى شريحة موجودة؛ لاحظ أنه حتى إذا كانت سعة الشريحة تسمح لك بإضافة عنصر إلى هذه الشريحة فلن يتم تعديل طولها ما لم تستخدم ()append.
</p>

<p>
	الدالة ()printSlice هي دالة مُساعدة، تُستخدم لطباعة عناصر معامل الشريحة الخاص بها، في حين أنّ الدالة ()negative تقوم بعمل معالجة لعناصر مُعامل الشريحة الخاص بها.
</p>

<p>
	ها هو ناتج <strong>slice.go</strong>:
</p>

<pre class="ipsCode">
$ go run slice.go
0 14 5 0 7 19
0 -14 -5 0 -7 -19
Before. Cap: 6, length: 6
After. Cap: 12, length: 7
0 -14 -5 0 -7 -19 -100
A new slice with 4 elements: 0 0 0 0
</pre>

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

<h2>
	الشرائح كمرجع للمصفوفات
</h2>

<p>
	تُتيح لك Go الاشارة إلى مصفوفة موجودة بشريحة باستخدام الترميز [:]. في هذه الحالة، ستنعكس أي تغييرات تجريها على دالة شريحة إلى المصفوفة - وهذا موضّح في refArray.go. يرجى تذكُّر أن الترميز [:] لا يُنشئ نسخة من المصفوفة، بل فقط يُشير إليها.
</p>

<p>
	الجزء الأكثر إثارة للاهتمام في <strong>refArray.go</strong> هو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2652_16" style="">
<span class="pln">func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        anArray </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">5</span><span class="pun">]</span><span class="pln">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="pun">-</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="pun">-</span><span class="lit">5</span><span class="pun">}</span><span class="pln">
        refAnArray </span><span class="pun">:=</span><span class="pln"> anArray</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">"Array:"</span><span class="pun">,</span><span class="pln"> anArray</span><span class="pun">)</span><span class="pln">
        printSlice</span><span class="pun">(</span><span class="pln">refAnArray</span><span class="pun">)</span><span class="pln">
        negative</span><span class="pun">(</span><span class="pln">refAnArray</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">"Array:"</span><span class="pun">,</span><span class="pln"> anArray</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ناتج <strong>refArray.go</strong> هو:
</p>

<pre class="ipsCode">
$ go run refArray.go
Array: [-1 2 -3 4 -5]
-1 2 -3 4 -5
Array: [1 -2 3 -4 5]
</pre>

<p>
	لذلك، تغيرت عناصر مجموعة anArray بسبب الإشارة إلى الشريحة.
</p>

<h2>
	الملخص
</h2>

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

<p>
	يمكنك العثور على كود Go الخاص بـ <strong>arrays.go</strong> و <strong>slice.go</strong> و <strong>refArray.go</strong> على <a href="https://github.com/mactsouk/opensource.com" rel="external nofollow">GitHub</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/article/18/7/introduction-go-arrays-and-slices" rel="external nofollow">An introduction to Go arrays and slices</a> لصاحبه Mihalis Tsoukalos
</p>
]]></description><guid isPermaLink="false">840</guid><pubDate>Wed, 26 Feb 2020 09:00:19 +0000</pubDate></item><item><title>3 &#x637;&#x631;&#x627;&#x626;&#x642; &#x644;&#x646;&#x633;&#x62E; &#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x641;&#x64A; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/3-ways-to-copy-files-in-Go.jpg.23b8af4b1215524141bbc981328d1664.jpg" /></p>

<p>
	ستتعلم في هذا المقال ثلاث طرائق الأكثر شيوعًا لنسخ ملف عبر لغة البرمجة Go.
</p>

<p>
	هذا المقال جزء من سلسلة Go التي كتبها Mihalis Tsoukalos. اقرأ الجزء 1: <a href="https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D9%85%D8%B1%D9%88%D8%B1-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%A2%D9%85%D9%86%D8%A9-%D9%81%D9%8A-go-r837/" rel=""> إنشاء كلمات مرور عشوائية وآمنة في Go</a>، والجزء 2: <a href="https://academy.hsoub.com/programming/go/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/" rel="">إنشاء خادم TCP متزامن في Go</a>.
</p>

<p>
	بالرغم من وجود أكثر من ثلاث طرق لنسخ ملف في Go، يُقدم هذا المقال الطرق الثلاثة الأكثر شيوعًا:
</p>

<ol>
<li>
		استخدام استدعاء دالة <strong>()io.copy</strong> من مكتبة Go.
	</li>
	<li>
		قراءة ملف الإدخال مرة واحدة وكتابته إلى ملف آخر.
	</li>
	<li>
		نسخ الملف في قطع صغيرة باستخدام مخزن مؤقت.
	</li>
</ol>
<h2>
	الطريقة الأولى: استخدام <strong>()io.copy</strong>
</h2>

<p>
	الإصدار الأول من هذه الطريقة يستخدم الدالة <strong>()io.copy</strong> من مكتبة Go. يمكنك العثور على منطق هذه الطريقة من خلال الإطّلاع على كود الدالة <strong>()copy</strong>، وهي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4703_6" style="">
<span class="pln">func copy</span><span class="pun">(</span><span class="pln">src</span><span class="pun">,</span><span class="pln"> dst string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int64</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">
        sourceFileStat</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">Stat</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"> </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"> </span><span class="pun">!</span><span class="pln">sourceFileStat</span><span class="pun">.</span><span class="typ">Mode</span><span class="pun">().</span><span class="typ">IsRegular</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="lit">0</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">"%s is not a regular file"</span><span class="pun">,</span><span class="pln"> src</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        source</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">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"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> err
        </span><span class="pun">}</span><span class="pln">
        defer source</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

        destination</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">dst</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"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> err
        </span><span class="pun">}</span><span class="pln">
        defer destination</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
        nBytes</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">destination</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> nBytes</span><span class="pun">,</span><span class="pln"> err
</span><span class="pun">}</span></pre>

<p>
	بصرف النظر عن اختبار ما إذا كان الملف الذي سيتم نسخه موجودًا (عبر <code>(os.Stat (src</code>)، وهو ملف عادي (يمكن التأكد عبر <code>sourceFileStat.Mode().IsRegular()‎</code>)، حتى تتمكن من فتحه للقراءة، يتم تنفيذ كل العمل بواسطة الجملة التعريفية <code>(io.copy(destination, Source</code> السابقة.
</p>

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

<p>
	يُمكنك معرفة المزيد عن <code>()io.copy</code> بالإطّلاع على صفحة التوثيق الخاصة بـالـ <a href="https://golang.org/pkg/io/" rel="external nofollow">io Package</a>.
</p>

<p>
	سيؤدي تنفيذ cp1.go إلى إنشاء النوع التالي من النواتج:
</p>

<pre class="ipsCode">
$ go run cp1.go
Please provide two command line arguments!
$ go run cp1.go fileCP.txt /tmp/fileCPCOPY
Copied 3826 bytes!
$ diff fileCP.txt /tmp/fileCPCOPY
</pre>

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

<h2>
	الطريقة الثانية: استخدام ()ioutil.WriteFile و ()ioutil.ReadFile
</h2>

<p>
	الطريقة الثانية لنسخ ملف هي استخدام الدوال <code>()ioutil.ReadFile</code> و <code>()ioutil.WriteFile</code>. تقرأ الدالة الأولى محتويات ملف بأكمله في شريحة بايت، بينما تقوم الدالة الثانية بكتابة محتويات شريحة بايت في ملف.
</p>

<p>
	يمكنك العثور على منطق هذه الطريقة في كود Go التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4703_8" style="">
<span class="pln">  input</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> ioutil</span><span class="pun">.</span><span class="typ">ReadFile</span><span class="pun">(</span><span class="pln">sourceFile</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">

        err </span><span class="pun">=</span><span class="pln"> ioutil</span><span class="pun">.</span><span class="typ">WriteFile</span><span class="pun">(</span><span class="pln">destinationFile</span><span class="pun">,</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0644</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">"Error creating"</span><span class="pun">,</span><span class="pln"> destinationFile</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></pre>

<p>
	بصرف النظر عن كتلتي if، التي تُعد جزءًا من طريقة عمل Go، تستطيع أن ترى أنّ الأداء الوظيفي للبرنامج موجود في كلٍ من <code>()ioutil.ReadFile</code> و <code>()ioutil.WriteFile</code>.
</p>

<p>
	سيؤدي تنفيذ cp2.go إلى إنشاء نوع الناتج التالي:
</p>

<pre class="ipsCode">
$ go run cp2.go
Please provide two command line arguments!
$ go run cp2.go fileCP.txt /tmp/copyFileCP
$ diff fileCP.txt /tmp/copyFileCP
</pre>

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

<h2>
	الطريقة الثالثة: استخدام ()os.read و ()os.write
</h2>

<p>
	الطريقة الثالثة لنسخ ملفات في Go، هي استخدام وسيلة <strong>cp3.go</strong> المُطوّرة في هذا القسم.
</p>

<p>
	تأخذ ثلاث معاملات:
</p>

<ol>
<li>
		اسم ملف الإدخال.
	</li>
	<li>
		اسم ملف الإخراج.
	</li>
	<li>
		حجم المخزن المؤقت.
	</li>
</ol>
<p>
	يتواجد الجزء الأكثر أهمية من cp3.go في الحلقة for التالية، والذي يمكن العثور عليه في الدالة ()<code>copy</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4703_11" style="">
<span class="pln">     buf </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="pln">byte</span><span class="pun">,</span><span class="pln"> BUFFERSIZE</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"> err </span><span class="pun">:=</span><span class="pln"> source</span><span class="pun">.</span><span class="typ">Read</span><span class="pun">(</span><span class="pln">buf</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">&amp;&amp;</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">
                        </span><span class="kwd">return</span><span class="pln"> err
                </span><span class="pun">}</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> n </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">
                        </span><span class="kwd">break</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"> err </span><span class="pun">:=</span><span class="pln"> destination</span><span class="pun">.</span><span class="typ">Write</span><span class="pun">(</span><span class="pln">buf</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"> 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></pre>

<p>
	تستخدم هذه التقنية الدالة <code>()os.read</code> لقراءة أجزاء صغيرة من ملف الإدخال في المخزن المؤقت المُسمى buf. وتستخدم الدالة <code>()os.write</code> لكتابة محتويات هذا المخزن المؤقت إلى ملف.
</p>

<p>
	تتوقف عملية النسخ عندما يكون هناك خطأ في القراءة أو عند الوصول إلى نهاية الملف (<code>io.EOF</code>).
</p>

<p>
	سيؤدي تنفيذ cp3.go إلى إنشاء نوع الناتج التالي:
</p>

<pre class="ipsCode">
$ go run cp3.go
usage: cp3 source destination BUFFERSIZE
$ go run cp3.go fileCP.txt /tmp/buf10 10
Copying fileCP.txt to /tmp/buf10
$ go run cp3.go fileCP.txt /tmp/buf20 20
Copying fileCP.txt to /tmp/buf20
</pre>

<p>
	كما سترى، يؤثر حجم المخزن المؤقت بشكل كبير على أداء cp3.go.
</p>

<h2>
	بعض من التقييم بهدف الموازنة
</h2>

<p>
	سيحاول الجزء الأخير من هذ المقال موازنة البرامج الثلاثة بالإضافة إلى أداء cp3.go لمختلف أحجام المخزن المؤقت باستخدام الأداة المساعدة لسطر الأوامر (time (1.
</p>

<p>
	يُظهر الناتج التالي أداء cp1.go و cp2.go و cp3.go عند نسخ ملف بحجم 500 ميجابايت:
</p>

<pre class="ipsCode">
$ ls -l INPUT
-rw-r--r--  1 mtsouk  staff  512000000 Jun  5 09:39 INPUT
$ time go run cp1.go INPUT /tmp/cp1
Copied 512000000 bytes!

real    0m0.980s
user    0m0.219s
sys     0m0.719s
$ time go run cp2.go INPUT /tmp/cp2

real    0m1.139s
user    0m0.196s
sys     0m0.654s
$ time go run cp3.go INPUT /tmp/cp3 1000000
Copying INPUT to /tmp/cp3

real    0m1.025s
user    0m0.195s
sys     0m0.486s
</pre>

<p>
	يُظهر الناتج أنّ أداء الأدوات المساعدة الثلاثة متشابه إلى حدٍ ما، مما يعني أن دوال مكتبة Go القياسية ذكية ومُحسَّنة تمامًا.
</p>

<p>
	الآن، دعنا نختبر كيف يؤثر حجم المخزن المؤقت على أداء cp3.go. سيؤدي تنفيذ cp3.go بحجم المخزن المؤقت 10 و 20 و 1000 بايت لنسخ ملف 500 ميجابايت على جهاز سريع إلى حد كبير لاستخراج النتائج التالية:
</p>

<pre class="ipsCode">
$ ls -l INPUT
-rw-r--r--  1 mtsouk  staff  512000000 Jun  5 09:39 INPUT
$ time go run cp3.go INPUT /tmp/buf10 10
Copying INPUT to /tmp/buf10

real    6m39.721s
user    1m18.457s
sys         5m19.186s
$ time go run cp3.go INPUT /tmp/buf20 20
Copying INPUT to /tmp/buf20

real    3m20.819s
user    0m39.444s
sys         2m40.380s
$ time go run cp3.go INPUT /tmp/buf1000 1000
Copying INPUT to /tmp/buf1000

real    0m4.916s
user    0m1.001s
sys     0m3.986s
</pre>

<p>
	يُظهر الناتج الذي تم إنشاؤه أنه كلما زاد حجم المخزن المؤقت، كلما كان أداء cp3.go أسرع، وهو أمر مُتوَقع إلى حدٍ ما. علاوةً على ذلك، يُعد استخدام أحجام المخازن المؤقتة أصغر من 20 بايت لنسخ الملفات الكبيرة عملية بطيئة للغاية ويجب تجنُّبها.
</p>

<p>
	يمكنك العثور على كود Go الخاص بـ cp1.go و cp2.go و cp3.go على <a href="https://github.com/mactsouk/opensource.com" rel="external nofollow">Github</a>.
</p>

<p>
	ترجمة وبتصرّف للمقال <a href="https://opensource.com/article/18/6/copying-files-go" rel="external nofollow">3 ways to copy files in Go</a>، لصاحبه Mihalis Tsoukalos.
</p>
]]></description><guid isPermaLink="false">839</guid><pubDate>Wed, 26 Feb 2020 08:38:43 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62E;&#x627;&#x62F;&#x645; &#x628;&#x631;&#x648;&#x62A;&#x648;&#x643;&#x648;&#x644; &#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x641;&#x64A; &#x627;&#x644;&#x625;&#x631;&#x633;&#x627;&#x644; TCP &#x645;&#x62A;&#x632;&#x627;&#x645;&#x646; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D8%A5%D8%B1%D8%B3%D8%A7%D9%84-tcp-%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-go-r838/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/02-Build-a-concurrent-Transmission-Control-Protocol-server-in-Go.jpg.4f27189c32a631db366f867e0b563162.jpg" /></p>

<p>
	سنعمل في هذا المقال على تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، إذ سأشرح كيفية تطوير خادم TCP متزامن، بلغة البرمجة Go، والتي تقوم بإرجاع أرقام عشوائية. إن لم تقرأ المقال السابق حول <a href="https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D9%85%D8%B1%D9%88%D8%B1-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%A2%D9%85%D9%86%D8%A9-%D9%81%D9%8A-go-r837/" rel="">إنشاء كلمات مرور عشوائية وآمنة في Go</a>، فننصحك بالرجوع إليه وقراءته أولًا.
</p>

<p>
	تعمل خوادم TCP و UDP بخدمة عملاء الشبكة في كل مكان عبر شبكات TCP / IP. لكل اتصال وارد من عميل TCP، سيقوم خادم TCP ببدء تشغيل goroutine جديد لمعالجة هذا الطلب.
</p>

<p>
	تستطيع إيجاد هذا المشروع <a href="https://github.com/mactsouk/opensource.com" rel="external nofollow">concTCP.go</a> على GitHub.
</p>

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

<p>
	يمكنك العثور على منطق البرنامج في دالة <code>()handleConnection</code> بلغة <strong>Go</strong>، والذي يتم تنفيذه على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8476_6" style="">
<span class="pln">func handleConnection</span><span class="pun">(</span><span class="pln">c net</span><span class="pun">.</span><span class="typ">Conn</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">"Serving %s\n"</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="typ">RemoteAddr</span><span class="pun">().</span><span class="typ">String</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">
                netData</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> bufio</span><span class="pun">.</span><span class="typ">NewReader</span><span class="pun">(</span><span class="pln">c</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">
                        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">

                temp </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">string</span><span class="pun">(</span><span class="pln">netData</span><span class="pun">))</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> temp </span><span class="pun">==</span><span class="pln"> </span><span class="str">"STOP"</span><span class="pln"> </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">

                result </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">random</span><span class="pun">())</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"\n"</span><span class="pln">
                c</span><span class="pun">.</span><span class="typ">Write</span><span class="pun">([]</span><span class="pln">byte</span><span class="pun">(</span><span class="pln">string</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">
        c</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا أرسل عميل TCP سلسلة التعليمات "STOP"، فسيتم إنهاء برنامج Go أي goroutine الذي يخدم عميل TCP محدد؛ وإلا، سيرسل خادم TCP رقمًا عشوائيًا إلى عميل TCP.
</p>

<p>
	تضمن الحلقة <code>for</code> أن عميل TCP سيتم خدمته طالما يُتَطلب ذلك. تقرأ الحلقة <code>for</code> الموجودة في كود Go البيانات من عميل TCP سطرًا بسطر باستخدام <code>('bufio.NewReader(c).ReadString('\n</code> وتُعيد إرسال البيانات باستخدام <code>(((c.Write([]byte(string(result</code>.
</p>

<h2>
	التزامن
</h2>

<p>
	تنفيذ دالة <code>()main</code>، يُعطي أمرًا لخادم TCP لبدء تشغيل برنامج goroutine جديد في كل مرة يتعين عليه خدمة عميل TCP:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8476_8" style="">
<span class="pln">func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        arguments </span><span class="pun">:=</span><span class="pln"> os</span><span class="pun">.</span><span class="typ">Args</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">arguments</span><span class="pun">)</span><span class="pln"> </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">
                fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="str">"Please provide a port number!"</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">

        PORT </span><span class="pun">:=</span><span class="pln"> </span><span class="str">":"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> arguments</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
        l</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> net</span><span class="pun">.</span><span class="typ">Listen</span><span class="pun">(</span><span class="str">"tcp4"</span><span class="pun">,</span><span class="pln"> PORT</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">
        defer l</span><span class="pun">.</span><span class="typ">Close</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">Unix</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">
                c</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> l</span><span class="pun">.</span><span class="typ">Accept</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">
                go handleConnection</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أولاً، تتأكد <code>()main</code> من أن البرنامج يحتوي على وسيطة سطر أوامر واحدة على الأقل.
</p>

<p>
	لاحظ أن الكود الموجود لا يتحقق مما إذا كانت وسيطة سطر الأوامر المحددة هي رقم مَنفذ TCP صالح أم لا. ومع ذلك، إذا لم تكن القيمة المحددة رقم منفذ TCP صالحًا، فسوف يفشل استدعاء <code>()net.Listen</code> مع ظهور رسالة خطأ مشابهة لما يلي:
</p>

<pre class="ipsCode">
$ go run concTCP.go 12a
listen tcp4: lookup tcp4/12a: nodename nor servname provided, or not known
$ go run concTCP.go -10
listen tcp4: address -10: invalid port
</pre>

<p>
	يتم استخدام استدعاء <code>()net.Listen</code> لإخبار برنامج Go بقبول اتصالات الشبكة وبالتالي كخادم. قيمة الإرجاع <code>()net.Listen</code> هي من النوع net.Conn، والتي تنفذ واجهات io.Reader و io.Writer.
</p>

<p>
	تقوم الدالة <code>()main</code> أيضًا باستدعاء الدالة <code>()rand.seed</code> لتهيئة مُنشئ الأرقام العشوائية.
</p>

<p>
	أخيرًا، تُتيح حلقة for للبرنامج الحفاظ على قبول عملاء TCP الجدد باستخدام <code>()accept</code> والتي سيتم معالجتها بواسطة نسخ الدالة <code>()handleConnection</code>، والتي يتم تنفيذها على شكل goroutines.
</p>

<h2>
	أول معامل للدالة ()net.Listen
</h2>

<p>
	يُحدد المعامل الأول من الدالة <strong>()net.Listen</strong> نوع الشبكة التي سيتم استخدامها، بينما يُحدد المعامل الثاني عنوان الخادم بالإضافة إلى رقم المَنفذ الذي سيستمع إليه الخادم.
</p>

<p>
	القيم الصالحة للمُعامل الأول هي:
</p>

<pre class="ipsCode" id="ips_uid_8476_10">
tcp, tcp4 (IPv4-only), tcp6 (IPv6-only), udp, udp4 (IPv4- only), udp6 (IPv6-only), ip, ip4 (IPv4-only), ip6 (IPv6-only), Unix (Unix sockets), Unixgram, Unixpacket
</pre>

<h2>
	فعالية خادم TCP المتزامن
</h2>

<p>
	يتطلب concTCP.go وسيطة سطر أوامر واحدة، وهي رقم المَنفذ الذي سيستمع إليه. سيكون الناتج الذي ستحصل عليه من concTCP.go عند خدمة عملاء TCP مشابهًا لما يلي:
</p>

<pre class="ipsCode">
$ go run concTCP.go 8001
Serving 127.0.0.1:62554
Serving 127.0.0.1:62556
</pre>

<p>
	يمكن لناتج <strong>(1)netStat</strong> التحقق من أن concTCP.go يخدم العديد من عملاء TCP أثناء الاستماع لمزيد من الاتصالات:
</p>

<pre class="ipsCode">
$ netstat -anp TCP | grep 8001
tcp4       0      0  127.0.0.1.8001         127.0.0.1.62556    ESTABLISHED
tcp4       0      0  127.0.0.1.62556        127.0.0.1.8001     ESTABLISHED
tcp4       0      0  127.0.0.1.8001         127.0.0.1.62554    ESTABLISHED
tcp4       0      0  127.0.0.1.62554        127.0.0.1.8001     ESTABLISHED
tcp4       0      0  *.8001                 *.*                    LISTEN
</pre>

<p>
	يعلمنا السطر الأخير من ناتج الأمر السابق أن هناك عملية تستمع إلى المَنفذ 8001، مما يعني أنه لا يزال بإمكانك الاتصال بمنفذ TCP رقم 8001. يتحقق أول سطرين من وجود اتصال شبكة TCP ثابت يستخدم أرقام المنافذ 8001 و 62556. وبالمثل، يتحقق السطران الثالث والرابع من وجود اتصال TCP آخر يستخدم أرقام المنافذ 8001 و 62554.
</p>

<p>
	تُظهر هذه الصورة ناتج concTCP.go عند خدمة العديد من عملاء TCP:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="34282" href="https://academy.hsoub.com/uploads/monthly_2020_02/2-TCPServer.PNG.bec2f91a11c1794828ad547c06ab5759.PNG" rel=""><img alt="2-TCPServer.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="34282" data-unique="yugkikrsl" src="https://academy.hsoub.com/uploads/monthly_2020_02/2-TCPServer.thumb.PNG.4208214255dbd44b9d5818d545cb6e18.PNG"></a>
</p>

<p>
	بشكل مشابه، تُظهر الصورة التالية الناتج من عميلين من TCP يتم تنفيذهما باستخدام <strong>(1)nc</strong>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_02/3-TCPClient.PNG.653f120be2e7573fa25cbe32c3d3ec67.PNG" data-fileid="34281" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="34281" data-unique="6kepfwont" src="https://academy.hsoub.com/uploads/monthly_2020_02/3-TCPClient.thumb.PNG.5d471a0bb668ebd73616387898fed3d1.PNG" alt="3-TCPClient.PNG"></a>
</p>

<p style="text-align: center;">
	 
</p>

<p>
	يُمكنك ايجاد معلومات أكثر عن <strong>(1)nc</strong>، والتي تُدعى أيضًا <strong>(1)netcat</strong> على <a href="https://en.wikipedia.org/wiki/Netcat" rel="external nofollow">ويكيبيديا</a>.
</p>

<h2>
	الملخص
</h2>

<p>
	لقد تعلمت للتو كيفية تطوير خادم TCP متزامن يقوم بإنشاء أرقام عشوائية باستخدام حوالي 65 سطرًا من كود Go، وهو أمر مثير للإعجاب جدًا!
</p>

<p>
	إذا كنت تريد أن يقوم خادم TCP بمهمة مختلفة، فقط قم بتغيير تنفيذ الدالة <strong>()handleConnection</strong>.
</p>

<p>
	ترجمة وبتصرّف للمقال <a href="https://opensource.com/article/18/5/building-concurrent-tcp-server-go" rel="external nofollow">Build a concurrent TCP server in Go</a>، لصاحبه Mihalis Tsoukalos.
</p>
]]></description><guid isPermaLink="false">838</guid><pubDate>Wed, 26 Feb 2020 08:12:58 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x643;&#x644;&#x645;&#x627;&#x62A; &#x645;&#x631;&#x648;&#x631; &#x639;&#x634;&#x648;&#x627;&#x626;&#x64A;&#x629; &#x648;&#x622;&#x645;&#x646;&#x629; &#x641;&#x64A; Go</title><link>https://academy.hsoub.com/programming/go/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D9%85%D8%B1%D9%88%D8%B1-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%A2%D9%85%D9%86%D8%A9-%D9%81%D9%8A-go-r837/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/5e561dd50669c_01-Creating-random-secure-passwords-in-Go.jpg.08f03408d6043c784523c2265d99a915.jpg" /></p>

<p>
	يعد مولد الأرقام العشوائية لـ Go طريقة رائعة لإنشاء كلمات مرور يصعب تخمينها. يمكنك استخدام مولد الأرقام العشوائية الذي توفره لغة البرمجة Go لإنشاء كلمات مرور يصعب تخمينها تتكون من رموز ASCII.
</p>

<p>
	على الرغم من أن الكود المقدَّم في هذا المقال سهل القراءة، إلا أنّه يُفضَّل أن تكون على معرفةٍ سابقة بأساسيات Go لفهمها. إذا كنت حديث العهد بلغات البرمجة، فاختر <a href="https://academy.hsoub.com/tags/%D9%85%D8%AF%D8%AE%D9%84%20%D8%A5%D9%84%D9%89%20%D9%84%D8%BA%D8%A9%20%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%20go/" rel="">مدخل إلى لغة البرمجة Go</a> لمعرفة المزيد حول Go، ثم عد إلى هنا.
</p>

<p>
	قبل التعمُّق في الأدوات المساعدة والكود الخاص بـ Go، ألقِ نظرة على هذه المجموعة الفرعية من جدول ASCII كما هو موجود في ناتج الأمر man ascii:
</p>

<pre class="ipsCode">
 30 40 50 60 70 80 90 100 110 120
 ---------------------------------
0:    (  2  &lt;  F  P  Z  d   n   x
1:    )  3  =  G  Q  [  e   o   y
2:    *  4  &gt;  H  R  \  f   p   z
3: !  +  5  ?  I  S  ]  g   q   {
4: "  ,  6  @  J  T  ^  h   r   |
5: #  -  7  A  K  U  _  i   s   }
6: $  .  8  B  L  V  `  j   t   ~
7: %  /  9  C  M  W  a  k   u  DEL
8: &amp;  0  :  D  N  X  b  l   v
9: '  1  ;  E  O  Y  c  m   w
</pre>

<p>
	القيم العشرية لرموز ASCII تتراوح من 33 إلى 126؛ لا توجد قيم ASCII أخرى مناسبة لتتواجد ضمن كلمات المرور. لذلك، سوف تنتج الأدوات المساعدة المقدَّمة في هذا المقال أحرف ASCII في هذا النطاق.
</p>

<h2>
	خلق أعداد صحيحة عشوائية
</h2>

<p>
	الأداة المساعدة الأولى تُدعى <code>random.go</code>، وتقوم بإنشاء عدد محدد من الأعداد الصحيحة العشوائية ضمن نطاق معين.
</p>

<p>
	الجزء الأكثر أهمية في <code>random.go</code> هو هذه الدالة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5918_9" style="">
<span class="pln">func random</span><span class="pun">(</span><span class="pln">min</span><span class="pun">,</span><span class="pln"> max int</span><span class="pun">)</span><span class="pln"> int </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> rand</span><span class="pun">.</span><span class="typ">Intn</span><span class="pun">(</span><span class="pln">max</span><span class="pun">-</span><span class="pln">min</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> min
</span><span class="pun">}</span></pre>

<p>
	تقوم هذه الدالّة بإنشاء أعداد صحيحة عشوائية تنتمي إلى نطاق معين باستخدام <code>()rand.intn</code>. لاحظ أنّ <code>rand.intn()‎</code> تقوم بإرجاع رقم عشوائي غير سالب ينتمي إلى المجال [0,n)، إذ n هو العدد المُمرَّر إلى الدالة. ستخرب الدالة إذا كان مُعاملها عددًا سالبًا وستكون رسالة الخطأ كما يلي:
</p>

<pre class="ipsCode">
panic: invalid argument to Intn
</pre>

<p>
	يُمكنك إيجاد توثيق المجموعة <strong>math/rand</strong> في هذا الرابط: <a href="https://golang.org/pkg/math/rand/" rel="external nofollow">math/rand Documentation</a>.
</p>

<p>
	تقبل الدالة <code>random.go</code> ثلاثًا من عوامل سطر الأوامر (Command Line Parameters):
</p>

<ol>
<li>
		<p>
			الحد الأدنى لقيمة الأعداد الصحيحة المراد توليدها.
		</p>
	</li>
	<li>
		<p>
			والقيمة القصوى.
		</p>
	</li>
	<li>
		<p>
			وعدد الأعداد الصحيحة التي سيتم توليدها.
		</p>
	</li>
</ol>
<p>
	تجميع وتنفيذ <code>random.go</code> سيخلق هذا النوع من الناتج:
</p>

<pre class="ipsCode">
$ go build random.go
$ ./random
Usage: ./random MIX MAX TOTAL
$ ./random 1 3 10
2 2 1 2 2 1 1 2 2 1
</pre>

<p>
	إذا كنت ترغب في إنشاء أرقام عشوائية أكثر أمانًا في Go، فاستخدم حزمة <strong>crypto / rand</strong> من مكتبة Go.
</p>

<h2>
	إنشاء كلمات مرور عشوائية
</h2>

<p>
	الأداة المساعدة الثانية <code>randomPass.go</code>، تنشئ كلمات مرور عشوائية. يستخدم <code>randomPass.go</code> الدالة <code>()random</code> لإنشاء أرقام عشوائية سيتم تحويلها إلى رموز ASCII باستخدام كود Go التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5918_12" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        myRand </span><span class="pun">:=</span><span class="pln"> random</span><span class="pun">(</span><span class="pln">MIN</span><span class="pun">,</span><span class="pln"> MAX</span><span class="pun">)</span><span class="pln">
        newChar </span><span class="pun">:=</span><span class="pln"> string</span><span class="pun">(</span><span class="pln">startChar</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"> byte</span><span class="pun">(</span><span class="pln">myRand</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">newChar</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"> LENGTH </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">
        i</span><span class="pun">++</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قيمة MIN هي 0 وقيمة MAX هي 94، في حين أن قيمة <code>startChar</code> هي !، وهو أول حرف قابل للطباعة في جدول ASCII (برمز ASCII العشري وهو 33). لذلك، توجد جميع أحرف ASCII التي سيتم إنشاؤها بعد ! وقبل الحرف ~، الذي يحتوي على رمز ASCII العشري لـلرقم 126.
</p>

<p>
	لذلك، كل رقم عشوائي يتم إنشاؤه أكبر من MIN، وأصغر من MAX، ويتم تحويله إلى رمز ASCII. تستمر العملية حتى تصبح كلمة المرور التي تم إنشاؤها لها بالطول المطلوب.
</p>

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

<pre class="ipsCode">
$ go run randomPass.go 1
Z
$ go run randomPass.go 10
#Cw^a#IwkT
$ go run randomPass.go
Using default values!
[PP8@'Ci
</pre>

<p>
	تفصيل أخير: لا تنس استعمال <code>()rand.seed</code> مع قيمة أولية لتهيئة مولد الأرقام العشوائية. إذا استخدمت نفس القيمة الأولية في كل وقت، فسيقوم مُولِّد الأرقام العشوائية بإنشاء نفس تسلسل الأعداد الصحيحة العشوائية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_02/2-RandomCodeGenerator.PNG.cf088c2e26e3a4960ad1811dd206529a.PNG" data-fileid="34279" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="34279" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/2-RandomCodeGenerator.PNG.cf088c2e26e3a4960ad1811dd206529a.PNG" alt="2-RandomCodeGenerator.PNG"></a>
</p>

<p>
	تستطيع إيجاد كلًا من <code>random.go</code> و <code>randomPass.go</code> على <a href="https://github.com/mactsouk/opensource.com" rel="external nofollow">GitHub</a>. وتستطيع أيضًا تنفيذ هذه الدوال على <a href="https://play.golang.org/" rel="external nofollow">play.golang.org</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/article/18/5/creating-random-secure-passwords-go" rel="external nofollow">Creating random, secure passwords in Go</a> لصاحبه <strong>Mihalis Tsoukalos</strong>.
</p>
]]></description><guid isPermaLink="false">837</guid><pubDate>Sun, 23 Feb 2020 08:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x648;&#x64A;&#x628; &#x628;&#x644;&#x63A;&#x629; Go &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62E;&#x627;&#x62F;&#x645; Nginx &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 18.04</title><link>https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-%D8%A8%D9%84%D8%BA%D8%A9-go-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1804-r747/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_10/5d983451d9438_go.jpg.cbee4c1bcdff7bd3b868d24f1934999f.jpg" /></p>

<p>
	أصبحت لغة <a href="https://golang.org/" rel="external nofollow">Go</a> -التي هي لغة برمجية عاميّة الغرض- واحدةً من لغات البرمجة الأكثر شعبيةً لتطوير الواجهة الخلفية. بالتركيز على البساطة، فإنَّ مصممي لغة Go ابتكروا لغةً سهلة التعلّم وأسرع من العديد من اللغات الأخرى لتطبيقات الويب، مستفيدين من الميزات الفعّالة مثل قدرتها على التعامل مع عدة طلبات في وقت واحد بسبب تزامنها. لهذا السبب، سيكون نشر تطبيق ويب بلغة Go مفيدًا للعديد من مطوري الواجهة الخلفية.
</p>

<p>
	<a href="https://www.nginx.com/" rel="external nofollow">Nginx</a> هو أحد أشهر خوادم الويب في العالم نظرًا لاستخدامه الخفيف للموارد وموثوقيته في حال وجود حمل زائد. تعتمد العديد من المواقع الضخمة والأكثر زيارةً على Nginx لتقدّم محتواها. في النشر، غالبًا ما يُستخدم Nginx موازن حمل(load balancer) أو وكيل عكسي (reverse proxy) لزيادة الأمان وجعل التطبيق أكثر قوة. بالتزامن مع لغة Go لتطوير الواجهة الخلفية في الويب، يمكن لخادم Nginx تقديم تطبيق ويب سريع وقوي.
</p>

<p>
	ستتعلم في هذا الدرس كيفية بناء تطبيق ويب <code>Hello World</code> بلغة Go وننشره على خادم أوبنتو 18.04 مستخدمين Nginx كخادم عكسي.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="32041" href="https://academy.hsoub.com/uploads/monthly_2019_10/5d98345401970_go.jpg.de745ff05164f0e6d5927ade922e2fc3.jpg" rel=""><img alt="كيف تنشر تطبيق ويب بلغة go.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="32041" data-unique="0jul2li90" src="https://academy.hsoub.com/uploads/monthly_2019_10/5d98345416a67_go.thumb.jpg.6cb1c2078e39ca1395ed69794b507124.jpg"></a>
</p>

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

<p>
	لمتابعة هذا الدرس، ستحتاج إلى ما يلي:
</p>

<ul>
<li>
		خادم أوبنتو 18.04 تم ضبطه باتباع <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">التهيئة الأولية لخادم أوبنتو 18.04</a>، متضمنًا مستخدمًا عاديًا بصلاحيات sudo وجدار حماية.
	</li>
	<li>
		يجب أن تكون لغة Go مثبّتة على حاسوبك.
	</li>
	<li>
		خادم <a href="https://www.nginx.com/" rel="external nofollow">Nginx</a> مثبّت باتّباع الدرس <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/" rel="">كيف تثبّت خادم Nginx على أوبنتو 18.04</a>. لا تتبع <a href="https://academy.hsoub.com/devops/servers/web/nginx/%d9%83%d9%8a%d9%81%d9%8a%d8%a9-%d8%aa%d8%ab%d8%a8%d9%8a%d8%aa-nginx-%d8%b9%d9%84%d9%89-%d8%a3%d9%88%d8%a8%d9%88%d9%86%d8%aa%d9%88-1804-r434/#-5-server-blocks-" rel="">الخطوة 5 - إعداد كتل الخادم</a>؛ ستنشئ كتلة خادم Nginx لاحقًا في هذا الدرس.
	</li>
	<li>
		اسم نطاق يشير إلى خادمك. سنستخدم <code>your_domain</code> في هذا الدرس. هذا ضروري للحصول على شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> لموقعك، حتى يمكنك أن تقدّم تطبيقك بأمان مع تشفير <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>.
	</li>
</ul>
<p>
	بالإضافة إلى ذلك، لتحقيق نشر بدرجة الإنتاج لتطبيق الويب Go، من المهم أن تحافظ على خادمك آمنًا بتثبيت شهادة <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>. أرشح لك هذه الخطوة بشدة. لتؤمّن تطبيق الويب Go، اتّبع <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D8%A4%D9%85%D9%91%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r365/" rel="">كيف تؤمّن خادم Nginx بشهادة Let's Encrypt على أوبنتو</a> بعد الخطوة 3 من هذا الدرس لتحصل على شهادة <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> مجانية.
</p>

<h2>
	الخطوة 1: بناء تطبيق ويب بلغة البرمجة Go
</h2>

<p>
	في هذه الخطوة، ستبني نموذج تطبيق ويب بلغة Go يعرض عبارة <code>Hello World</code> على نطاقك <code>your_domain</code> ويقوم بتحيّة المستخدم على الرابط <code>your_domain/greet/</code>. إذا كنت تريد تعلّم المزيد من أساسيات البرمجة في Go، تفحّص مقالتنا <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>.
</p>

<p>
	بدايةً، أنشئ مجلد جديد في مجلد <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="">GOPATH</a> ليتضمن الملف المصدري. يمكنك تسمية المجلد بأي اسم تريده، ولكن في هذا الدرس سنستخدم اسم <code>go-web</code>:
</p>

<pre class="ipsCode">
$ mkdir $GOPATH/go-web
</pre>

<p>
	باتّباع بنية الملف المقترحة في درس <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>، سيعطي هذا مجلدك المسار <code>‎~/go/go-web</code>:
</p>

<p>
	بعد ذلك، نفّذ التعليمة التالية لتغيّر المجلد إلى مجلدك الذي أنشأته حديثًا في <code>GOPATH</code>:
</p>

<pre class="ipsCode">
$ cd $GOPATH/go-web
</pre>

<p>
	استخدم محرر النصوص nano أو المحرر المفضل لك لإنشاء ملف باسم <code>main.go</code>، والذي سيتضمن الشيفرة المصدرية لتطبيقك الويب:
</p>

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

<p>
	لإنشاء وظيفة التطبيق <code>Hello World</code>، أضف شيفرة Go التالية إلى ملف <code>main.go</code> المنشأ حديثًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_7" 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">"net/http"</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">
    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</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">Fprintf</span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello World"</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="str">"/greet/"</span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</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"> r</span><span class="pun">.</span><span class="pln">URL</span><span class="pun">.</span><span class="typ">Path</span><span class="pun">[</span><span class="pln">len</span><span class="pun">(</span><span class="str">"/greet/"</span><span class="pun">):]</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Fprintf</span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello %s\n"</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">

    http</span><span class="pun">.</span><span class="typ">ListenAndServe</span><span class="pun">(</span><span class="str">":9990"</span><span class="pun">,</span><span class="pln"> nil</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	كتبت أولًا نقطة الدخول إلى تطبيقك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_9" style="">
<span class="pln">package main
</span><span class="pun">…</span></pre>

<p>
	تخبر تعليمة <code>package main</code> مُصرِّف Go أن يصرّف هذا الملف على أنّه برنامجٌ تنفيذي بدلًا من أن يكون مكتبة مشتركة (shared library).
</p>

<p>
	ثمّ لديك تعليمات <code>import</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_11" style="">
<span class="pun">…</span><span class="pln">

</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">"net/http"</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
</span><span class="pun">…</span></pre>

<p>
	يستورد هذا الجزء الوحدات الضرورية لعمل هذه الشيفرة، والتي تشمل حزمة <code>fmt</code> القياسية وحزمة <code>net/http</code> لخادم الويب الخاص بك.
</p>

<p>
	يُنشئ الجزء التالي مسارك الأول في الدالة <code>main</code> والتي هي نقطة الدخول لأي تطبيق Go:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_13" style="">
<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">
    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="str">"/"</span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</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">Fprintf</span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello World"</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>
	أنشئ المسار الأب <code>/</code> ضمن الدالة <code>func main</code>، التي ستعيد النص <code>Hello World</code> عندما تُطلب.
</p>

<p>
	كما هو موضح في الجزء التالي فإنّ المسار الثاني يقبل معاملًا في الرابط (URL parameter)، في هذه الحالة اسمًا، لعرضه مصحوبًا بالتحية.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_15" style="">
<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">
    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="str">"/greet/"</span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</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"> r</span><span class="pun">.</span><span class="pln">URL</span><span class="pun">.</span><span class="typ">Path</span><span class="pun">[</span><span class="pln">len</span><span class="pun">(</span><span class="str">"/greet/"</span><span class="pun">):]</span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Fprintf</span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello %s\n"</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="pun">…</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">…</span></pre>

<p>
	يستخدم هذا <code>URL.Path</code> الخاص بلغة Go لتخزين القيمة مباشرةً بعد <code>/greet/</code> وتمريرها كاسم من معامل الرابط.
</p>

<p>
	أخيرًا، هيّئ الخادم:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5652_17" style="">
<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">
  http</span><span class="pun">.</span><span class="typ">ListenAndServe</span><span class="pun">(</span><span class="str">":9990"</span><span class="pun">,</span><span class="pln"> nil</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يشغّل الجزء السابق الخادم ويعرض تطبيقك عبر المنفذ <code>9990</code> باستخدام خادم <code>http</code> المدمج بلغة Go.
</p>

<p>
	احفظ الملف وأغلق المحرر النصي بمجرد الانتهاء من فحص الشيفرة في <code>main.go</code>.
</p>

<p>
	بعد ذلك، ابنِ الملف الثنائي القابل للتنفيذ لتطبيقك باستخدام الأمر:
</p>

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

<p>
	التعليمة السابقة ستصرِّف الملف <code>main.go</code> لإنتاج ملف قابل للتنفيذ باسم <code>main</code>.
</p>

<p>
	لقد أنشأت نموذج تطبيق ويب بلغة Go. بعد ذلك، ستنشئ ملف وحدة systemd ليبقى تطبيقك شغّالًا في الخلفية حتى عندما لا تصل إلى خادمك.
</p>

<h2>
	الخطوة 2: إنشاء ملف وحدة Systemd
</h2>

<p>
	في هذه الخطوة، ستنشئ ملف وحدة <a href="https://academy.hsoub.com/devops/linux/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-systemd-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AE%D8%AF%D9%85%D8%A7%D8%AA%D8%8C-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-units%D8%8C-%D9%88%D8%A7%D9%84%D9%8A%D9%88%D9%85%D9%8A%D8%A7%D8%AA-journal-r130/" rel="">systemd</a> ليبقى تطبيقك شغّالًا في الخلفية حتى عندما يسجّل المستخدم خروجه من الخادم. سيجعل هذا تطبيقك ثابتًا، مما يجعلك أقرب بخطوة للنشر على مستوى الإنتاج.
</p>

<p>
	بدايةً، أنشئ ملفًا جديدًا في مجلد <code>‎/lib/systemd/system</code> باسم <code>goweb.service</code> باستخدام محرر النصوص nano أو محرر النصوص المفضّل لك:
</p>

<pre class="ipsCode">
$ sudo nano /lib/systemd/system/goweb.service
</pre>

<p>
	لضبط معاملات الخدمة، أضف الجزء التالي في الملف.
</p>

<pre class="ipsCode">
[Unit]
Description=goweb

[Service]
Type=simple
Restart=always
RestartSec=5s
ExecStart=/home/user/go/go-web/main

[Install]
WantedBy=multi-user.target
</pre>

<p>
	يحدّد المتغير <code>ExecStart=/home/user/go/go-web/main</code> أنَّ نقطة الدخول لهذه الخدمة عبر الملف <code>main</code> القابل للتنفيذ الموجود في المجلد <code>‎/home/user/go/go-web</code>، إذ <code>user</code> هو اسم المستخدم لحساب المستخدم العادي الذي يملك صلاحيات sudo على الخادم. <code>Restart=always</code> تضمن أنَّ systemd سيحاول دائمًا أن يعيد تشغيل البرنامج إذا توقف. في السطر التالي، <code>RestartSec=5s</code> يضبط وقت انتظار لخمس ثوانٍ بين محاولات إعادة التشغيل. يحدِّد <code>WantedBy=multi-user.target</code> في أي حالة سيفعّل الخادم الخدمة.
</p>

<p>
	احفظ وأغلق الملف.
</p>

<p>
	بعد أن كتبت ملف وحدة الخدمة، شغّل خدمة الويب Go باستخدام الأمر:
</p>

<pre class="ipsCode">
$ sudo service goweb start
</pre>

<p>
	للتأكّد فيما إذا كانت الخدمة شغّالة، استخدم الأمر التالي:
</p>

<pre class="ipsCode">
$ sudo service goweb status
</pre>

<p>
	ستستقبل الخرج التالي:
</p>

<pre class="ipsCode">
Output
● goweb.service - goweb
   Loaded: loaded (/lib/systemd/system/goweb.service; disabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-07-17 23:28:57 UTC; 6s ago
 Main <abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr>: 1891 (main)
    Tasks: 4 (limit: 1152)
   CGroup: /system.slice/goweb.service
           └─1891 /home/user/go/go-web/main
</pre>

<p>
	لتتعلم المزيد عن العمل مع ملف وحدة systemd، ألقِ نظرة على <a href="https://academy.hsoub.com/devops/linux/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-systemd-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AE%D8%AF%D9%85%D8%A7%D8%AA%D8%8C-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-units%D8%8C-%D9%88%D8%A7%D9%84%D9%8A%D9%88%D9%85%D9%8A%D8%A7%D8%AA-journal-r130/" rel="">فهم وحدات وملفات وحدة Systemd</a>.
</p>

<p>
	الآن بعد أن أصبح لديك تطبيقًا شغّالًا، يمكنك ضبط الوكيل العكسي Nginx.
</p>

<h2>
	الخطوة 3: ضبط وكيل عكسي مع Nginx
</h2>

<p>
	ستنشئ في هذه الخطوة كتلة خادم Nginx وستضبط الوكيل العكسي Nginx لتعرض تطبيقك على الإنترنت.
</p>

<p>
	أولًا، غيّر مجلد العمل الخاص بك إلى مجلد <code>sites-available</code> على الخادم Nginx:
</p>

<pre class="ipsCode">
$ cd /etc/nginx/sites-available
</pre>

<p>
	أنشئ ملفًا جديدًا باسم النطاق الذي تريد عرض تطبيقك عليه. سيستخدم هذا الدرس الملف <code>your_domain</code>:
</p>

<pre class="ipsCode">
$ sudo nano your_domain
</pre>

<p>
	أضف الأسطر التالية إلى الملف لوضع الإعدادات لـ <code>your_domain</code>:
</p>

<pre class="ipsCode">
server {
    server_name your_domain www.your_domain;

    location / {
        proxy_pass http://localhost:9990;
    }
}
</pre>

<p>
	كتلة الخادم Nginx تستخدم <a href="http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass" rel="external nofollow">proxy_pass</a> لتقديم تطبيق الويب Go على عنوان IP لخادمك المشار إليه على أنّه مضيف محلي <code>localhost</code> لتشغيله على المنفذ <code>9990</code> . يشير <code>server_name</code> إلى اسم النطاق المعيّن لعنوان IP الخاص بك، في هذه الحالة <code>your_domain</code> و<code>www.your_domain</code>.
</p>

<p>
	بعد ذلك، أنشئ رابطًا رمزيًا لإعدادات Nginx هذه في مجلد <code>sites-enabled</code> بتشغيل الأمر التالي:
</p>

<pre class="ipsCode">
$ sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/your_domain
</pre>

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

<p>
	بعدها، أعد تحميل إعدادات Nginx بتشغيل تعليمة إعادة التحميل:
</p>

<pre class="ipsCode">
$ sudo nginx -s reload
</pre>

<p>
	لتتأكد أن نشرك يعمل، قم بزيارة <code>http://your_domain</code> في متصفحك، إذ ستتم تحيتك بسلسلة نصية Hello World.
</p>

<p>
	ملاحظة: كما ذُكر في قسم المتطلبات الأساسية، يُنصح في هذه النقطة أن يتم تفعيل <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> على خادمك. سيضمن ذلك تشفير جميع الاتصالات بين التطبيق وزوّاره، وهو أمر مهم بشكلٍ خاص إذا طلب التطبيق معلومات حساسة مثل تسجيل الدخول أو كلمة المرور. اتّبع الآن درس <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D8%A4%D9%85%D9%91%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r365/" rel="">كيف تؤمّن خادم Nginx بشهادة Let's Encrypt على أوبنتو</a> لتحصل على شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> مجانية لخادم Nginx على أوبنتو 18.04. بعد أن تحصل على شهادات <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> خاصة بك، عُد وأكمل هذا الدرس.
</p>

<p>
	ضبطت الآن الوكيل العكسي Nginx لتعرض تطبيقك على اسم النطاق الخاص بك، وقمت بتأمين تطبيق الويب Go مع <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>. في الخطوة التالية، ستختبر تطبيقك عبر اتصالٍ آمن.
</p>

<h2>
	الخطوة 4: اختبار التطبيق
</h2>

<p>
	في هذه الخطوة، ستختبر تطبيقك عبر اتصالٍ آمن لتتأكد من أنَّ كل شيء يعمل.
</p>

<p>
	افتح متصفح الويب المفضل لك، وقم بزيارة <code>https://your_domain</code>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="32039" href="https://academy.hsoub.com/uploads/monthly_2019_10/pic01.png.25800e572281bb336be6e8e0a2ee2740.png" rel=""><img alt="pic01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="32039" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2019_10/pic01.thumb.png.854b3385522cc2cb9466a1c13e643865.png"></a>
</p>

<p>
	ستستقبل رسالة <code>Hello World</code> بسيطة. استقبال هذه الرسالة عند استخدام <code>https://‎</code> في الرابط يشير إلى أنَّ التطبيق يُعرض عبر اتصالٍ آمن.
</p>

<p>
	بعد ذلك، حاول زيارة المسار الثاني <code>https://your_domain/greet/your-name</code> مستبدلًا بالعبارة <code>your-name</code> أيّ اسم آخر تريد أن يلقي عليه تطبيقك التحيّة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="32040" href="https://academy.hsoub.com/uploads/monthly_2019_10/pic02.png.b78512ceffb33db7c0c62de7e6aec90c.png" rel=""><img alt="pic02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="32040" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2019_10/pic02.thumb.png.f1cd4c24e4179e953dd07b4c76627205.png"></a>
</p>

<p>
	سيعيد التطبيق تحيّة بسيطة مع <code>your-name</code>، الذي يعتمد على المعامل الممرّر للرابط.
</p>

<p>
	حالما تستقبل هذه النتائج، تكون قد نشرت تطبيق ويب Go بنجاح.
</p>

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

<p>
	في هذا الدرس، أنشأت تطبيق ويب بسيط بلغة Go مستخدمًا مكاتبها القياسية، وقمت بضبط وكيل عكسي مستخدمًا Nginx، واستخدمت شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> على نطاقك لتأمين تطبيقك. لتتعلّم المزيد حول Go، تفحّص <a href="https://golang.org/doc/" rel="external nofollow">توثيقها الرسمي</a>. بإمكانك أيضًا أن تلقي نظرة على <a href="https://academy.hsoub.com/programming/go/" rel="">قسم لغة GO</a> لتتعلم المزيد حول البرمجة بهذه اللغة الفعالة.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-go-web-application-using-nginx-on-ubuntu-18-04" rel="external nofollow">How To Deploy a Go Web Application Using Nginx on Ubuntu 18.04</a> لصاحبه Michael Okoh
</p>
]]></description><guid isPermaLink="false">747</guid><pubDate>Sat, 05 Oct 2019 06:20:07 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x646;&#x634;&#x626; &#x633;&#x646;&#x62F;&#x64B;&#x627; &#x62E;&#x644;&#x641;&#x64A;&#x651;&#x64B;&#x627; Backend &#x62E;&#x637;&#x648;&#x629; &#x62E;&#x637;&#x648;&#x629; &#x628;&#x644;&#x63A;&#x629; Go</title><link>https://academy.hsoub.com/programming/go/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%A6-%D8%B3%D9%86%D8%AF%D9%8B%D8%A7-%D8%AE%D9%84%D9%81%D9%8A%D9%91%D9%8B%D8%A7-backend-%D8%AE%D8%B7%D9%88%D8%A9-%D8%AE%D8%B7%D9%88%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-go-r539/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_09/59c65b8820f1f_main(53).png.13b885a59b555b015d25f365fe40201d.png" /></p>

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

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

<h2 id="إعداد-بيئة-العمل">
	إعداد بيئة العمل
</h2>

<p>
	الخطوة الأولى هي - بالطبع - تثبيتُ Go. يمكن تثبيت Go من المستودعات الرسمية على توزيعات لينكس؛ مثلا بالنسبة لأوبونتو:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
sudo apt install golang-go</pre>

<p>
	إصدارات Go الموجودة في المستودعات الرسمية تكون في العادة أقدم قليلا من تلك الموجودة على الموقع الرسمي، إلا أنها تؤدي الغرض؛ علاوة على سهولة التثبيت. يمكنك تثبيت إصدارات أحدث على أوبونتو (<a href="how-to-install-go-1-6-on-ubuntu-16-04" rel="">هنا</a>) وCentos (<a href="how-to-install-go-1-7-on-centos-7" rel="">هنا</a>).
</p>

<p>
	بالنسبة لمستخدمي نظام Mac OS فيمكنهم تثبيت اللغة عن طريق Homebrew:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs cmake"><span class="pln">brew </span><span class="hljs-keyword"><span class="pln">install</span></span><span class="pln"> go</span></code></pre>

<p>
	يحوي الموقع الرسمي كذلك الملفات التنفيذية لتثبيت اللغة على أغلب أنظمة التشغيل، بما في ذلك ويندوز.
</p>

<p>
	تأكّد من تثبيت Go بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs livecodeserver"><span class="pln">go </span><span class="hljs-built_in"><span class="pln">version</span></span></code></pre>

<p>
	مثال لنتيجة اﻷمر أعلاه (على توزيعة أوبونتو):
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs livecodeserver"><span class="pln">go </span><span class="hljs-built_in"><span class="pln">version</span></span><span class="pln"> go1</span><span class="hljs-number"><span class="pun">.</span><span class="lit">6</span></span><span class="hljs-number"><span class="lit">.2</span></span><span class="pln"> linux</span><span class="pun">/</span><span class="pln">amd64</span></code></pre>

<p>
	– روابط للتثبيت على وندوز وإعداد المسارات –
</p>

<p>
	توجد الكثير من محرّرات النصوص والإضافات المتاحة لكتابة شفرات Go. أفضّل شخصيّا محرّر الشفرات Sublime Text وإضافة GoSublime؛ إلا أن طريقة كتابة Go تتيح استخدام محرّرات نصوص عاديّة بسهولة خصوصا للمشاريع الصغيرة. أعمل مع محترفين يقضون كامل اليوم في البرمجة بلغة Go باستخدام محرّر النصوص Vim، دون أي إضافة لإبراز صيغة الشفرات البرمجية Syntax highlighting. بالتأكيد لن تحتاج لأكثر من محرّر نصوص بسيط للبدء في تعلّم Go.
</p>

<h2 id="مشروع-جديد">
	مشروع جديد
</h2>

<p>
	إن لم تكن أنشأت مجلّدا للعمل أثناء تثبيت Go وإعداده فالوقت مناسب لذلك.<br>
	تتوقّع أدوات Go أن توجد جميع الشفرات البرمجية على المسار <code>GOPATH/src$</code>، وبالتالي سيكون عملنا دائما في هذا المجلّد. يمكن لمجموعة أدوات Go كذلك أن تتخاطب مع مشاريع مُضيَّفة على مواقع مثل GitHub وBitbucket إن أُعدّت لذلك.
</p>

<p>
	سننشئ لأغراض هذا الدرس مستودعا جديدا فارغا على GitHub ولنسمّه “hello” (أو أي اسم يناسبك). ننشئ مجلّدا ضمن مجلّد <code>GOPATH</code> لاستقبال ملفات المستودع (أبدل <code>your-username</code> باسم المستخدم الخاصّ بك على GitHub):
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs lasso"><span class="pln">mkdir </span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">p</span></span><span class="pln"> </span><span class="hljs-variable"><span class="pln">$GOPATH</span></span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">github</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">com</span><span class="pun">/</span><span class="pln">your</span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">username</span></span><span class="pln">
cd </span><span class="hljs-variable"><span class="pln">$GOPATH</span></span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">github</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">com</span><span class="pun">/</span><span class="pln">your</span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">username</span></span></code></pre>

<p>
	ننسخ المستودع ضمن المجلّد الذي أنشأناه أعلاه:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs bash"><span class="pln">git clone git@github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">:</span><span class="pln">your</span><span class="pun">-</span><span class="pln">username</span><span class="pun">/</span><span class="pln">hello
</span><span class="hljs-built_in"><span class="pln">cd</span></span><span class="pln"> hello</span></code></pre>

<p>
	سننشئ الآن ملفا باسم <code>main.go</code> ليحوي برنامجا قصيرا بلغة Go:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="kwd">package</span></span><span class="pln"> main

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-built_in"><span class="pln">println</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"hello!"</span></span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	نفّذ الأمر <code>go build</code> لتصريف جميع محتويات المجلّد الحالي. سينتُج ملف تنفيذي بنفس الاسم؛ يمكنك بعدها طلب تشغيله بذكر اسمه على النحو التالي:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> build
</span><span class="pun">./</span><span class="pln">hello</span></code></pre>

<p>
	النتيجة:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs erlang-repl"><span class="hljs-function_or_atom"><span class="pln">hello</span></span><span class="hljs-exclamation_mark"><span class="pun">!</span></span></code></pre>

<p>
	ما زلت رغم سنوات من التطوير بلغة Go أبدأ مشاريعي بنفس الطريقة: مستودع Git فارغ، ملف <code>main.go</code> وبضعة أوامر.
</p>

<p>
	يصبح أي تطبيق يتبع الطرق المتعارف عليها لتنظيم شفرة Go قابلا للتثبيت بسهولة بالأمر <code>go get</code>. إن أودعت على سبيل المثال الملف أعلاه ودفعته إلى مستودع Git فإن أي شخص لديه بيئة عمل Go يمكنه تنفيذ الخطوتين التاليتين لتشغيل البرنامج:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs lasso"><span class="pln">go </span><span class="kwd">get</span><span class="pln"> github</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">com</span><span class="pun">/</span><span class="pln">your</span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">username</span></span><span class="pun">/</span><span class="pln">hello
</span><span class="hljs-variable"><span class="pln">$GOPATH</span></span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">hello</span></code></pre>

<h2 id="إنشاء-خادوم-وب">
	إنشاء خادوم وب
</h2>

<p>
	فلنجعل برنامجنا البسيط السابق خادوم وب:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="kwd">package</span></span><span class="pln"> main

</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"net/http"</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="hljs-string"><span class="str">"/"</span></span><span class="pun">,</span><span class="pln"> hello</span><span class="pun">)</span><span class="pln">
    http</span><span class="pun">.</span><span class="typ">ListenAndServe</span><span class="pun">(</span><span class="hljs-string"><span class="str">":8080"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> hello</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    w</span><span class="pun">.</span><span class="typ">Write</span><span class="pun">([]</span><span class="hljs-typename"><span class="kwd">byte</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"hello!"</span></span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	هناك بضعة سطور تحتاج للشرح.
</p>

<p>
	نحتاج أولا لاستيراد الحزمة <code>net/http</code>من المكتبة المعيارية لـGo:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"net/http"</span></span></code></pre>

<p>
	ثم نثبّت دالة معالجة Handler function في المسار الجذر لخادوم الوِب. تتعامل <code>http.HandleFunc</code> مع الموجّه المبدئي لطلبات Http في Go، وهو ServeMux.
</p>

<pre class="ipsCode" id="ips_uid_7209_9">
http.HandleFunc("/", hello)</pre>

<p>
	الدالة <code>hello</code> هي من النوع <code>http.HandlerFunc</code> الذي يسمح باستخدام دوال عاديّة على أنها دوال معالجة لطلبات HTTP. للدوال من النوع <code>http.HandlerFunc</code> توقيع Signature خاص (توقيع الدالة هو المعطيات المُمرَّرة لها وأنواع البيانات التي تُرجعها هذه الدالة) ويمكن تمريرها في معطى إلى الدالة <code>HandleFunc</code> التي تسجّل الدالة المُمرَّرة في المُعطى لدى الموجِّه ServeMux، وبالتالي يُنشئ خادوم الوِب، في كلّ مرة يصله فيها طلب جديد يطابق المسار الجذر، يُنشئ نسخة جديدة من الدالة <code>hello</code>.
</p>

<p>
	تستقبل الدالة <code>hello</code> متغيّرا من النوع <code>http.ResponseWriter</code> الذي تستخدمه الدالة المُعالِجة لإنشاء إجابة HTTP وبالتالي إنشاء ردّ على طلب العميل عن طريق التابع <code>Write</code> الذي يوفّره النوع <code>http.ResponseWriter</code>. بما أن التابع <code>http.ResponseWriter.Write</code> يأخذ معطى عامًّا من النوع <code>[]byte</code> أو <code>byte-slice</code>، فنحوّل السلسة النصيّة <code>hello</code> إلى النوع المناسب:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs livecodeserver"><span class="pln">func hello</span><span class="pun">(</span><span class="pln">w </span><span class="hljs-keyword"><span class="pln">http</span></span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="hljs-keyword"><span class="pln">http</span></span><span class="pun">.</span><span class="typ">Request</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    w</span><span class="pun">.</span><span class="typ">Write</span><span class="pun">([]</span><span class="hljs-keyword"><span class="kwd">byte</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"hello!"</span></span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	في الأخير نشغّل خادوم وب على المنفذ <code>8080</code> عبر الدالة <code>http.ListenAndServe</code> التي تستقبل معطيَين، الأول هو المنفَذ Port والثاني دالة معالجة. إذا كانت قيمة المعطى الثاني هي <code>nil</code> فهذا يعني أننا نريد استخدام الموجّه المبدئي <code>DefaultServeMux</code>. هذا الاستدعاء متزامن Synchronous، أو معترِض Blocking، يبقي البرنامج قيد التشغيل إلى أن يُقطَع الاستدعاء.
</p>

<p>
	صرّف وشغّل البرنامج بنفس الطريقة السابقة:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> build
</span><span class="pun">./</span><span class="pln">hello</span></code></pre>

<p>
	افتح سطر أوامر - طرفيّة - آخر وأرسل طلب HTTP إلى المنفذ <code>8080</code>:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs cs"><span class="pln">curl http</span><span class="pun">:</span><span class="hljs-comment"><span class="com">//localhost:8080</span></span></code></pre>

<p>
	النتيجة:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs erlang-repl"><span class="hljs-function_or_atom"><span class="pln">hello</span></span><span class="hljs-exclamation_mark"><span class="pun">!</span></span></code></pre>

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

<h2 id="إضافة-مسارات-جديدة">
	إضافة مسارات جديدة
</h2>

<p>
	يمكننا فعل أمور أكثر أهمية من مجرّد قول مرحبا (hello). فليكن المُدخَل اسم مدينة نستخدمه لاستدعاء واجهة تطبيقات برمجيّة <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لأحوال الطقس ونعيد توجيه الإجابة - درجة الحرارة - في الرد على الطلب. توفّر خدمة OpenWeatherMap واجهة تطبيقات برمجيّة مجانيّة وسهلة الاستخدام للحصول على توقّعات مناخية. سجّل في الموقع للحصول على مفتاح <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>. يمكن الاستعلام من <a href="https://openweathermap.org/" rel="external nofollow">OpenWeatherMap</a> حسب المدن. تُرجع واجهة التطبيقات البرمجية إجابة على النحو التالي (عدّلنا قليلا على النتيجة):
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs json"><span class="pun">{</span><span class="pln">
    </span><span class="str">"</span><span class="hljs-attribute"><span class="str">name</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-string"><span class="str">"Tokyo"</span></span></span><span class="pun">,</span><span class="pln">
    </span><span class="str">"</span><span class="hljs-attribute"><span class="str">coord</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="pun">{</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">lon</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">139.69</span></span></span><span class="pun">,</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">lat</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">35.69</span></span><span class="pln">
    </span></span><span class="pun">}</span></span><span class="pun">,</span><span class="pln">
    </span><span class="str">"</span><span class="hljs-attribute"><span class="str">weather</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"</span><span class="hljs-attribute"><span class="str">id</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">803</span></span></span><span class="pun">,</span><span class="pln">
            </span><span class="str">"</span><span class="hljs-attribute"><span class="str">main</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-string"><span class="str">"Clouds"</span></span></span><span class="pun">,</span><span class="pln">
            </span><span class="str">"</span><span class="hljs-attribute"><span class="str">description</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-string"><span class="str">"broken clouds"</span></span></span><span class="pun">,</span><span class="pln">
            </span><span class="str">"</span><span class="hljs-attribute"><span class="str">icon</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-string"><span class="str">"04n"</span></span><span class="pln">
        </span></span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span></span><span class="pun">,</span><span class="pln">
    </span><span class="str">"</span><span class="hljs-attribute"><span class="str">main</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="pun">{</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">temp</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">296.69</span></span></span><span class="pun">,</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">pressure</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">1014</span></span></span><span class="pun">,</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">humidity</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">83</span></span></span><span class="pun">,</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">temp_min</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">295.37</span></span></span><span class="pun">,</span><span class="pln">
        </span><span class="str">"</span><span class="hljs-attribute"><span class="str">temp_max</span></span><span class="str">"</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-value"><span class="hljs-number"><span class="lit">298.15</span></span><span class="pln">
    </span></span><span class="pun">}</span><span class="pln">
</span></span><span class="pun">}</span></code></pre>

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

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> weatherData </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"name"`</span></span><span class="pln">
    </span><span class="typ">Main</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Kelvin</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"temp"`</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"main"`</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	تعرّف الكلمة المفتاحية <code>type</code> بنية بيانات جديدة نسمّيها <code>weatherData</code> ونصرّح بكونها من النوع <code>struct</code>. يحوي كلّ حقل في المتغيّرات من نوع <code>struct</code> اسما (مثلا <code>Name</code> أو <code>Main</code>)، نوع بيانات (string أو struct آخر مجهول الاسم) وما يُعرَف بالوسم Tag. تشبه الوسوم في Go البيانات الوصفية Metadata، وتمكّننا من استخدام الحزمة <code>encoding/json</code> لإعادة صفّ الإجابة التي تقدّمها خدمة OpenWeatherMap وحفظها في بنية البيانات التي أعددناها. يتطلّب الأمر كتابة شفرة برمجية أكثر ممّا عليه الحال في لغات برمجيّة ذات أنواع ديناميكية للبيانات (بمعنى أنه يمكن استخدام متغيّر فور احتياجنا له دون الحاجة للتصريح بنوع البيانات) مثل <a href="https://academy.hsoub.com/programming/ruby/" rel="">روبي</a> و<a href="https://academy.hsoub.com/programming/python/" rel="">بايثون</a>، إلا أنه يمنحنا خاصيّة الأمان في نوع البيانات.
</p>

<p>
	عرّفنا بنية البيانات، نحتاج الآن لطريقة تمكّننا من ملْء هذه البنية بالبيانات القادمة من واجهة التطبيقات البرمجية؛ سنكتُب دالة لهذا الغرض.
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="pln">
</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> query</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">weatherData</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">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">Get</span><span class="pun">(</span><span class="hljs-string"><span class="str">"http://<abbr title="Application Programming Interface | واجهة برمجية">api</abbr>.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&amp;q="</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> city</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> weatherData</span><span class="pun">{},</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> d weatherData

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> json</span><span class="pun">.</span><span class="typ">NewDecoder</span><span class="pun">(</span><span class="pln">resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">).</span><span class="typ">Decode</span><span class="pun">(&amp;</span><span class="pln">d</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> weatherData</span><span class="pun">{},</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> d</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	تأخذ الدالة سلسلة محارف تمثّل المدينة وتُرجِع متغيّرا من بنية بيانات <code>weatherData</code> وخطأ. هذه هي الطريقة الأساسية للتعامل مع الأخطاء في Go. تغلّف الدوال سلوكا معيَّنا، ويمكن أن يخفق هذا السلوك. بالنسبة لمثالنا، يمكن أن يخفق طلب <code>GET</code> الذي نرسله لـOpenWeatherMap لأسباب عدّة، وقد تكون البيانات المُرجَعة غير تلك التي ننتظرها. نُرجِع في كلتا الحالتين خطأ غير فارغ Non-nil للعميل الذي يُنتظَر منه أن يتعامل مع هذا الخطأ بما يتناسب مع السياق الذي أرسل فيه الطلب.
</p>

<p>
	إن نجح الطلب <code>http.Get</code> نؤجّل طلبا لغلق متن الإجابة لننفّذه بعد الخروج من نطاق Scope الدالة (أي بعد الرجوع من دالة طلب HTTP)، وهي طريقة أنيقة لإدارة الموارد. في أثناء ذلك نحجز بنية <code>weatherData</code> ونستخدم <code>json.Decoder</code> لقراءة بيانات الإجابة وإدخالها مباشرة في بنيتنا.
</p>

<p>
	عندما تنجح إعادة صياغة بيانات الإجابة نعيد المتغيّر <code>weatherData</code> إلى المُستدعي مع خطأ فارغ للدلالة على نجاح العملية. ننتقل الآن إلى ربط تلك الدالة بالدالة المعالجة للطلب:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs avrasm"><span class="pln">http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">HandleFunc</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"/weather/"</span></span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ResponseWriter</span></span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Request</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    city </span><span class="pun">:=</span><span class="pln"> strings</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">SplitN</span></span><span class="pun">(</span><span class="pln">r</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">URL</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Path</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"/"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">)[</span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">]</span><span class="pln">

    data</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> query</span><span class="pun">(</span><span class="pln">city</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"> </span><span class="kwd">nil</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Error</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> err</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Error</span></span><span class="pun">(),</span><span class="pln"> http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">StatusInternalServerError</span></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">

    w</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Header</span></span><span class="pun">()</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Set</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"Content-Type"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"application/json; charset=utf-8"</span></span><span class="pun">)</span><span class="pln">
    json</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">NewEncoder</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Encode</span></span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></code></pre>

<p>
	نعرّف دالة معالجة على السطر In-line بدلا من تعريفها منفصلة. نستخدم الدالة <code>strings.SplitN</code> لأخذ كل ما يوجد بعد <code>/weather/</code> في المسار والتعامل معه على أنه اسم مدينة. ننفّذ الطلب وإن صادفتنا أخطاء نعلم العميل بها باستخدام الدالة المساعدة <code>http.Error</code>، ونوقف تنفيذ الدالة للدلالة على اكتمال طلب HTTP. إن لم يوجد خطأ نخبر العميل بأننا بصدد إرسال بيانات JSON إليه ونستخدم الدالة <code>json.NewEncode</code> لترميز محتوى <code>weatherData</code> بصيغة JSON مباشرة.
</p>

<p>
	الشفرة لحدّ الساعة أنيقة، تعتمد أسلوبا إجرائيا Procedural ويسهل فهمها. لا مجال للخطأ في تفسيرها ولا يمكنها تجاوز الأخطاء الشائعة. إن نقلنا الدالة المعالجة لـ <code>"hello, world"</code> إلى المسار <code>hello/</code> واستوردنا الحزم المطلوبة فسنحصُل على البرنامج المُكتمل التالي:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="kwd">package</span></span><span class="pln"> main

</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="hljs-string"><span class="str">"encoding/json"</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"net/http"</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"strings"</span></span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="hljs-string"><span class="str">"/hello"</span></span><span class="pun">,</span><span class="pln"> hello</span><span class="pun">)</span><span class="pln">

    http</span><span class="pun">.</span><span class="typ">HandleFunc</span><span class="pun">(</span><span class="hljs-string"><span class="str">"/weather/"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        city </span><span class="pun">:=</span><span class="pln"> strings</span><span class="pun">.</span><span class="typ">SplitN</span><span class="pun">(</span><span class="pln">r</span><span class="pun">.</span><span class="pln">URL</span><span class="pun">.</span><span class="typ">Path</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"/"</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">3</span></span><span class="pun">)</span><span class="hljs-number"><span class="pun">[</span><span class="lit">2</span></span><span class="pun">]</span><span class="pln">

        data</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> query</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            http</span><span class="pun">.</span><span class="typ">Error</span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> err</span><span class="pun">.</span><span class="typ">Error</span><span class="pun">(),</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">StatusInternalServerError</span><span class="pun">)</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        w</span><span class="pun">.</span><span class="typ">Header</span><span class="pun">().</span><span class="typ">Set</span><span class="pun">(</span><span class="hljs-string"><span class="str">"Content-Type"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"application/json; charset=utf-8"</span></span><span class="pun">)</span><span class="pln">
        json</span><span class="pun">.</span><span class="typ">NewEncoder</span><span class="pun">(</span><span class="pln">w</span><span class="pun">).</span><span class="typ">Encode</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    http</span><span class="pun">.</span><span class="typ">ListenAndServe</span><span class="pun">(</span><span class="hljs-string"><span class="str">":8080"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> hello</span><span class="pun">(</span><span class="pln">w http</span><span class="pun">.</span><span class="typ">ResponseWriter</span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="pun">.</span><span class="typ">Request</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    w</span><span class="pun">.</span><span class="typ">Write</span><span class="pun">([]</span><span class="hljs-typename"><span class="kwd">byte</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"hello!"</span></span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> query</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">weatherData</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">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">Get</span><span class="pun">(</span><span class="hljs-string"><span class="str">"http://<abbr title="Application Programming Interface | واجهة برمجية">api</abbr>.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&amp;q="</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> city</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> weatherData</span><span class="pun">{},</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> d weatherData

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> json</span><span class="pun">.</span><span class="typ">NewDecoder</span><span class="pun">(</span><span class="pln">resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">).</span><span class="typ">Decode</span><span class="pun">(&amp;</span><span class="pln">d</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> weatherData</span><span class="pun">{},</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> d</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> weatherData </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Name</span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"name"`</span></span><span class="pln">
    </span><span class="typ">Main</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Kelvin</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"temp"`</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"main"`</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	نصرّف البرنامج وننفّذه بنفس الطريقة التي شرحناها أعلاه:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> build
</span><span class="pun">./</span><span class="pln">hello</span></code></pre>

<p>
	نفتح طرفيّة أخرى ونطلب المسار <code><a href="http://localhost:8080/weather/tokyo" ipsnoembed="false" rel="external nofollow">http://localhost:8080/weather/tokyo</a></code> (الحرارة بمقياس كلفن):
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs cs"><span class="pln">curl http</span><span class="pun">:</span><span class="hljs-comment"><span class="com">//localhost:8080/weather/tokyo</span></span></code></pre>

<p>
	النتيجة:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs json"><span class="pun">{</span><span class="str">"</span><span class="hljs-attribute"><span class="str">name</span></span><span class="str">"</span><span class="pun">:</span><span class="hljs-value"><span class="hljs-string"><span class="str">"Tokyo"</span></span></span><span class="pun">,</span><span class="str">"</span><span class="hljs-attribute"><span class="str">main</span></span><span class="str">"</span><span class="pun">:</span><span class="hljs-value"><span class="pun">{</span><span class="str">"</span><span class="hljs-attribute"><span class="str">temp</span></span><span class="str">"</span><span class="pun">:</span><span class="hljs-value"><span class="hljs-number"><span class="lit">295.9</span></span></span><span class="pun">}</span></span><span class="pun">}</span></code></pre>

<h3 id="الاستعلام-من-واجهات-برمجية-عدة">
	الاستعلام من واجهات برمجية عدّة
</h3>

<p>
	ربما من الممكن الحصول على درجات حرارة أكثر دقّة إن استعلمنا من خدمات طقس عدّة وحسبنا المتوسّط بينها. تتطلّب أغلب الواجهات البرمجية لخدمات الطقس التسجيل. سنضيف خدمة Weather Underground، لذا <a href="https://www.wunderground.com/signup?optin=on" rel="external nofollow">سجّل في هذه الخدمة</a> واعثر على مفاتيح الاستيثاق الضرورية لاستخدام واجهة التطبيقات البرمجية.
</p>

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

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> weatherProvider </span><span class="hljs-keyword"><span class="kwd">interface</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="hljs-comment"><span class="com">// in Kelvin, naturally</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	يمكننا الآن تحويل دالة الاستعلام من openWeatherMap السابقة إلى نوع بيانات يوافق الواجهة <code>weatherProvider</code>. بما أننا لا نحتاج لحفظ أي حالة لإجراء طلب HTTP GET فسنستخدم بنية <code>struct</code> فارغة، وسنضيف سطرا قصيرا في دالة الاستعلام الجديدة لتسجيل ما يحدُث عند الاتصال بالخدمات لمراجعته في ما بعد:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> openWeatherMap </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pun">{}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">w openWeatherMap</span><span class="pun">)</span><span class="pln"> temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></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">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">Get</span><span class="pun">(</span><span class="hljs-string"><span class="str">"http://<abbr title="Application Programming Interface | واجهة برمجية">api</abbr>.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&amp;q="</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> city</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> d </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Main</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Kelvin</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"temp"`</span></span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"main"`</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> json</span><span class="pun">.</span><span class="typ">NewDecoder</span><span class="pun">(</span><span class="pln">resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">).</span><span class="typ">Decode</span><span class="pun">(&amp;</span><span class="pln">d</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    log</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="hljs-string"><span class="str">"openWeatherMap: %s: %.2f"</span></span><span class="pun">,</span><span class="pln"> city</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="typ">Main</span><span class="pun">.</span><span class="typ">Kelvin</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> d</span><span class="pun">.</span><span class="typ">Main</span><span class="pun">.</span><span class="typ">Kelvin</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	لا نريد سوى استخراج درجة الحرارة (بالكلفن) من الإجابة، لذا يمكننا تعريف بنية <code>struct</code> على السطر Inline. في ما عدا ذلك فإن الشفرة البرمجية مشابهة لدالة الاستعلام السابقة، ولكنّها معرَّفة على صيغة تابع Method لبنية <code>openWeatherMap</code>. تتيح لنا هذه الطريقة استخدام عيّنة Instance من <code>openWeatherMap</code> مكان الواجهة <code>weatherProvider</code>.
</p>

<p>
	سنفعل نفس الشيء بالنسبة لخدمة Weather Underground. الفرق الوحيد مع الخدمة السابقة هو أننا سنخزّن مفتاح الواجهة البرمجية في بنية <code>struct</code> ثم نستخدمه في التابع.
</p>

<p>
	يجدر ملاحظة أن Weather Underground لا تعالج أسماء المدن المتطابقة بنفس جودة تعامل Open WeatherMap، وهو ما ينبغي الانتباه إليه في التطبيقات الفعلية. لن نعالج هذا الأمر في مثالنا البسيط هذا.
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> weatherUnderground </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    apiKey </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">w weatherUnderground</span><span class="pun">)</span><span class="pln"> temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></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">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="pun">.</span><span class="typ">Get</span><span class="pun">(</span><span class="hljs-string"><span class="str">"http://<abbr title="Application Programming Interface | واجهة برمجية">api</abbr>.wunderground.com/<abbr title="Application Programming Interface | واجهة برمجية">api</abbr>/"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> w</span><span class="pun">.</span><span class="pln">apiKey </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"/conditions/q/"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> city </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">".json"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">.</span><span class="typ">Close</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> d </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Observation</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">struct</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Celsius</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"temp_c"`</span></span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-string"><span class="str">`json:"current_observation"`</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> json</span><span class="pun">.</span><span class="typ">NewDecoder</span><span class="pun">(</span><span class="pln">resp</span><span class="pun">.</span><span class="typ">Body</span><span class="pun">).</span><span class="typ">Decode</span><span class="pun">(&amp;</span><span class="pln">d</span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
    </span><span class="pun">}</span><span class="pln">

    kelvin </span><span class="pun">:=</span><span class="pln"> d</span><span class="pun">.</span><span class="typ">Observation</span><span class="pun">.</span><span class="typ">Celsius</span><span class="pln"> </span><span class="pun">+</span><span class="hljs-number"><span class="pln"> </span><span class="lit">273.15</span></span><span class="pln">
    log</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="hljs-string"><span class="str">"weatherUnderground: %s: %.2f"</span></span><span class="pun">,</span><span class="pln"> city</span><span class="pun">,</span><span class="pln"> kelvin</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> kelvin</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	لدينا الآن مزوّدا خدمة طقس. فلنكتب دالّة تستعلم من الاثنين وتعيد متوسّط درجة الحرارة. سنكفّ - حفاظا على بساطة المثال - عن الاستعلام إذا واجهتنا مشكلة في الحصول على بيانات من الخدمتين.
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">,</span><span class="pln"> providers </span><span class="pun">...</span><span class="pln">weatherProvider</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></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">
    sum </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">0.0</span></span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> provider </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">range</span></span><span class="pln"> providers </span><span class="pun">{</span><span class="pln">
        k</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> provider</span><span class="pun">.</span><span class="pln">temperature</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
        </span><span class="pun">}</span><span class="pln">

        sum </span><span class="pun">+=</span><span class="pln"> k
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> sum </span><span class="pun">/</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">providers</span><span class="pun">)),</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	لاحظ أن تعريف الدالة قريب جدّا من تعريف التابع <code>temperature</code> المُعرَّف في الواجهة <code>weatherProvider</code>. إن جمعنا الواجهات <code>weatherProvider</code> في نوع بيانات ثم عرّفنا تابعا باسم <code>temperature</code> على هذا النوع فسيمكننا إنشاء نوع جديد يجمع الواجهات <code>weatherProvider</code>.
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> multiWeatherProvider </span><span class="pun">[]</span><span class="pln">weatherProvider

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">w multiWeatherProvider</span><span class="pun">)</span><span class="pln"> temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></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">
    sum </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">0.0</span></span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> provider </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">range</span></span><span class="pln"> w </span><span class="pun">{</span><span class="pln">
        k</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> provider</span><span class="pun">.</span><span class="pln">temperature</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> err
        </span><span class="pun">}</span><span class="pln">

        sum </span><span class="pun">+=</span><span class="pln"> k
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> sum </span><span class="pun">/</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">)),</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	رائع! سنتمكّن من تمرير <code>multiWeatherProvider</code> إلى أي دالة تقبل <code>weatherProvider</code>.
</p>

<p>
	نربُط الآن خادوم HTTP بدالة <code>temperature</code> للحصول على درجات الحرارة عند طلب مسار به اسم مدينة:
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs avrasm"><span class="pln">func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    mw </span><span class="pun">:=</span><span class="pln"> multiWeatherProvider</span><span class="pun">{</span><span class="pln">
        openWeatherMap</span><span class="pun">{},</span><span class="pln">
        weatherUnderground</span><span class="pun">{</span><span class="pln">apiKey</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"your-key-here"</span></span><span class="pun">},</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">HandleFunc</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"/weather/"</span></span><span class="pun">,</span><span class="pln"> func</span><span class="pun">(</span><span class="pln">w http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ResponseWriter</span></span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Request</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">begin</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> time</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Now</span></span><span class="pun">()</span><span class="pln">
        city </span><span class="pun">:=</span><span class="pln"> strings</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">SplitN</span></span><span class="pun">(</span><span class="pln">r</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">URL</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Path</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"/"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">)[</span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">]</span><span class="pln">

        temp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> mw</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">temperature</span></span><span class="pun">(</span><span class="pln">city</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"> </span><span class="kwd">nil</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Error</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">,</span><span class="pln"> err</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Error</span></span><span class="pun">(),</span><span class="pln"> http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">StatusInternalServerError</span></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">

        w</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Header</span></span><span class="pun">()</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Set</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"Content-Type"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"application/json; charset=utf-8"</span></span><span class="pun">)</span><span class="pln">
        json</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">NewEncoder</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Encode</span></span><span class="pun">(</span><span class="pln">map</span><span class="pun">[</span><span class="kwd">string</span><span class="pun">]</span><span class="kwd">interface</span><span class="pun">{}{</span><span class="pln">
            </span><span class="hljs-string"><span class="str">"city"</span></span><span class="pun">:</span><span class="pln"> city</span><span class="pun">,</span><span class="pln">
            </span><span class="hljs-string"><span class="str">"temp"</span></span><span class="pun">:</span><span class="pln"> temp</span><span class="pun">,</span><span class="pln">
            </span><span class="hljs-string"><span class="str">"took"</span></span><span class="pun">:</span><span class="pln"> time</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Since</span></span><span class="pun">(</span><span class="kwd">begin</span><span class="pun">)</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">String</span></span><span class="pun">(),</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ListenAndServe</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">":8080"</span></span><span class="pun">,</span><span class="pln"> </span><span class="kwd">nil</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></code></pre>

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

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs cs"><span class="pun">./</span><span class="pln">hello
</span><span class="hljs-number"><span class="lit">2015</span></span><span class="pun">/</span><span class="hljs-number"><span class="lit">01</span></span><span class="pun">/</span><span class="hljs-number"><span class="lit">01</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">13</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">14</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">15</span></span><span class="pln"> openWeatherMap</span><span class="pun">:</span><span class="pln"> tokyo</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">295.46</span></span><span class="pln">
</span><span class="hljs-number"><span class="lit">2015</span></span><span class="pun">/</span><span class="hljs-number"><span class="lit">01</span></span><span class="pun">/</span><span class="hljs-number"><span class="lit">01</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">13</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">14</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">16</span></span><span class="pln"> weatherUnderground</span><span class="pun">:</span><span class="pln"> tokyo</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">273.15</span></span><span class="pln">

$ curl http</span><span class="pun">:</span><span class="hljs-comment"><span class="com">//localhost:8080/weather/tokyo</span></span><span class="pln">
</span><span class="pun">{</span><span class="hljs-string"><span class="str">"city"</span></span><span class="pun">:</span><span class="hljs-string"><span class="str">"tokyo"</span></span><span class="pun">,</span><span class="hljs-string"><span class="str">"temp"</span></span><span class="pun">:</span><span class="hljs-number"><span class="lit">284.30499999999995</span></span><span class="pun">,</span><span class="hljs-string"><span class="str">"took"</span></span><span class="pun">:</span><span class="hljs-string"><span class="str">"821.665230ms"</span></span><span class="pun">}</span></code></pre>

<h2 id="جعل-الاستعلامات-تعمل-بالتوازي">
	جعل الاستعلامات تعمل بالتوازي
</h2>

<p>
	نكتفي لحدّ الساعة بالاستعلام من الواجهات البرمجية بالتتالي، الواحدة تلو الأخرى. لا يوجد ما يمنعنا من الاستعلام من الواجهتيْن البرمجيّتين في نفس الوقت، وهو ما سياسهم في تقليل الوقت اللازم للإجابة.
</p>

<p>
	نستفيد من إمكانات Go في التشغيل المتزامن عبر وحدات Go الفرعية goroutines والقنوات Channels. سنضع كل استعلام في وحدة فرعية خاصّة به ثم نشغّلها بالتوازي. نجمع الإجابات بعد ذلك في قناة واحدة ثم نحسب المعدّلات عندما تكتمل جميع الاستعلامات.
</p>

<pre class="ipsCode" id="ips_uid_7209_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">w multiWeatherProvider</span><span class="pun">)</span><span class="pln"> temperature</span><span class="pun">(</span><span class="pln">city </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-typename"><span class="pln">float64</span></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="hljs-comment"><span class="com">// ننشئ قناتيْن، واحدة لدرجات الحرارة والأخرى للأخطاء</span></span><span class="pln">
    </span><span class="hljs-comment"><span class="com">// يُضيف كل مزوّد خدمة قيمة إلى إحدى القناتيْن فقط</span></span><span class="pln">
    temps </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">))</span><span class="pln">
    errs </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">))</span><span class="pln">

    </span><span class="hljs-comment"><span class="com">// نطلق بالنسبة لكلّ مزوّد خدمة وحدة فرعية جديدة بدالة مجهولة الاسم. تستدعي الدالة مجهولة الاسم التابع temperature ثم تعيد توجيه النتيجة المتحصًّل عليها.</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> provider </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">range</span></span><span class="pln"> w </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">(</span><span class="pln">p weatherProvider</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            k</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> p</span><span class="pun">.</span><span class="pln">temperature</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                errs </span><span class="pun">&lt;-</span><span class="pln"> err
                </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            temps </span><span class="pun">&lt;-</span><span class="pln"> k
        </span><span class="pun">}(</span><span class="pln">provider</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    sum </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">0.0</span></span><span class="pln">

    </span><span class="hljs-comment"><span class="com">// نجمع درجات الحرارة - أو الأخطاء في حالة وجودها - من كل خِدمة </span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> i </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">w</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="hljs-keyword"><span class="kwd">select</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> temp </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">temps</span><span class="pun">:</span><span class="pln">
            sum </span><span class="pun">+=</span><span class="pln"> temp
        </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">errs</span><span class="pun">:</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="hljs-number"><span class="pln"> </span><span class="lit">0</span></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="hljs-comment"><span class="com">// نُرجع الحرارة كما في السابق</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> sum </span><span class="pun">/</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">len</span></span><span class="pun">(</span><span class="pln">w</span><span class="pun">)),</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	يساوي الوقت اللازم الآن لتنفيذ جميع الاستعلامات المدة الزمنية اللازمة للحصول على إجابة من أبطأ خدمة طقس؛ بدلا من مجموع المدد الزمنية لجميع الاستعلامات كما كان سابقا. كل ما احتجنا له هو تعديل سلوك <code>multiWeatherProvider</code> الذي ما زال مع ذلك يُرضي حاجات واجهة <code>weatherProvider</code> البسيطة وغير المتوازية.
</p>

<h2 id="السهولة">
	السهولة
</h2>

<p>
	انتقلنا ببضع خطوات وبالاقتصار فقط على المكتبة المعيارية لـGo من مثال “hello world” إلى خادوم سند خلفي Backend server يحترم مبادئ REST. يمكن نشر الشفرة التي كتبناها على أي معمارية خواديم تقريبا. الملف التنفيذي الناتج سريع ويتضمّن جميع ما يحتاجه للعمل؛ والأهم من ذلك، الشفرة البرمجيّة واضحة لقراءتها وفهمها. كما تمكن صيانتها وتمديدها بسهولة حسب الحاجة. أنا مقتنع أن كلّ هذه الميزات هي نتيجة لتفاني Go في البساطة.
</p>

<p>
	ترجمة - بتصرّف - للمقال <a href="http://howistart.org/posts/go/1/index.html" rel="external nofollow">How I start Go</a> لصاحبه Peter Bourgon.
</p>
]]></description><guid isPermaLink="false">539</guid><pubDate>Tue, 26 Sep 2017 16:08:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x644;&#x64A;&#x644; &#x627;&#x644;&#x633;&#x631;&#x64A;&#x639; &#x625;&#x644;&#x649; &#x644;&#x63A;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_09/59b98a497bb3b_main(34).png.a9dca135e728514d112e07b4432ae33d.png" /></p>

<p>
	أُنشئت لغة البرمجة Go لإنجاز العمل بسهولة، وهي ليست ضمن الاتجاهات الحديثة في علم الحاسوب، ولكنها أحدث وسيلة برمجية لحل المشاكل في الواقع بسرعة.<br>
	تمتلك لغة Go مفاهيم مُشابهة للغات البرمجة الإجبارية Imperative Languages بالإضافة لثبات أنواع البيانات Static typing، وتعدّ كذلك سريعة في البرمجة Compilation وسريعة في التشغيل والتنفيذ، ومتوافقة مع المعالجات ذات الأنوية المتعددة بهدف الاستفادة منها بسهولة، كما أنها تمتلك الكثير من المزايا التي تساعد في البرمجة للأنظمة الكبيرة والمعقَّدة.<br>
	تتمتع لغة Go بمكتبة معيارية عظيمة ومجتمع برمجي متحمس ونشط.<br>
	في هذا المقال، سوف نشرح أساسيات لغة Go بطريقة سهلة وبسيطة، ونُعرج على بعض المفاهيم المهمة. الشفرة البرمجية الموجودة في هذا المقال مترابطة، ولكننا قسّمناها إلى أجزاء ووضعنا عناوين لهذه الأجزاء، كما توجد الكثير من التعليقات المباشرة على الشفرة البرمجية.<br>
	المواضيع الأساسية التي يغطيها هذا المقال كالتالي:
</p>

<ol>
<li>
		كتابة التعليقات.
	</li>
	<li>
		المكتبات واستيرادها.
	</li>
	<li>
		الدوال.
	</li>
	<li>
		أنواع البيانات.
	</li>
	<li>
		القيم الراجعة المسماة.
	</li>
	<li>
		المتغيرات والذاكرة.
	</li>
	<li>
		جمل التحكم.
	</li>
	<li>
		توليد الدوال.
	</li>
	<li>
		التنفيذ المؤجل.
	</li>
	<li>
		الواجهات.
	</li>
	<li>
		المُدخلات المتعددة.
	</li>
	<li>
		معالجة الأخطاء.
	</li>
	<li>
		التنفيذ المتزامن.
	</li>
	<li>
		الويب
	</li>
</ol>
<h2 id="كتابة-التعليقات">
	كتابة التعليقات
</h2>

<p>
	لكتابة تعليق من سطر واحد
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
// single line comment</pre>

<p>
	لكتابة تعليق بأكثر من سطر
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs cs"><span class="hljs-comment"><span class="com">/* Multi-
 line comment */</span></span></code></pre>

<h2 id="المكتبات-واستيرادها">
	المكتبات واستيرادها
</h2>

<p>
	يبدأ كل ملف مصدري بالكلمة المفتاحية packag. تُستخدَم الكلمة المفتاحية main لتعريف الملف كملف تشغيلي وليس مكتبة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs lua"><span class="hljs-built_in"><span class="kwd">package</span></span><span class="pln"> main</span></code></pre>

<p>
	لاستيراد حزمة مكتبية في الملف نستخدم التعليمة <code>Import</code> بالطريقة التالية:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="hljs-string"><span class="str">"fmt"</span></span><span class="pln"> </span><span class="hljs-comment"><span class="com">// حزمة في المكتبة المعيارية للغة</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"io/ioutil"</span></span><span class="pln"> </span><span class="hljs-comment"><span class="com">// تطبق دوال إدخال وإخراج</span></span><span class="pln">
    m </span><span class="hljs-string"><span class="str">"math"</span></span><span class="pln">    </span><span class="hljs-comment"><span class="com">//نستخدم الحرف m لاختصار اسم مكتبة الدوال الرياضية</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"net/http"</span></span><span class="pln">  </span><span class="hljs-comment"><span class="com">// خادوم ويب</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"os"</span></span><span class="pln">        </span><span class="hljs-comment"><span class="com">// دوال على مستوى نظام التشغيل مثل التعامل مع الملفات</span></span><span class="pln">
    </span><span class="hljs-string"><span class="str">"strconv"</span></span><span class="pln">   </span><span class="hljs-comment"><span class="com">// تحويلات نصية</span></span><span class="pln">
</span><span class="pun">)</span></code></pre>

<h2 id="الدوال-functions">
	الدوال Functions
</h2>

<p>
	تُعرَّف الدوال باستخدام كلمة func متبوعة باسم الدالة.<br>
	تعدّ الدالة main خاصة، وهي المدخل للملف التنفيذي للبرنامج (لغة Go تستخدم الأقواس المزخرفة {} لتحديد الأجزاء/الكتل البرمجية).
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs scss"><span class="pln">func </span><span class="hljs-function"><span class="pln">main</span><span class="pun">()</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// لإخراج نص على وحدة الإخراج (العرض) الرئيسية stdout نستخدم الدالة Println الموجودة في مكتبة fmt</span></span><span class="pln">
 fmt</span><span class="hljs-class"><span class="pun">.</span><span class="typ">Println</span></span><span class="pun">(</span><span class="str">"Hello world!"</span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// استدعاء دالة من نفس الحزمة الحالية</span></span><span class="pln">
 </span><span class="hljs-function"><span class="pln">beyondHello</span><span class="pun">()</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	تحتاج الدوال لأقواس تستقبل المعاملات Parameters، وحتى في عدم وجود معاملات فإن الأقواس مطلوبة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs scilab"><span class="pln">func beyondHello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// تعريف متغير (لا بد من تعريف المتغير قبل استخدامه)</span></span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> x </span><span class="kwd">int</span><span class="pln"> 
</span><span class="hljs-comment"><span class="com">// إعطاء قيمة للمتغير</span></span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln">     
</span><span class="hljs-comment"><span class="com">// التعريف القصير باستخدام := ويشمل تعريف المتغير, وتحديد نوعه وإعطاءه قيمة</span></span><span class="pln">
    y </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// دالة ترجع قيمتين منفصلتين</span></span><span class="pln">
 </span><span class="hljs-built_in"><span class="pln">sum</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">prod</span></span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> learnMultiple</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">        

</span><span class="hljs-comment"><span class="com">// طباعة وإخراج بشكل بسيط ومباشر</span></span><span class="pln">
    </span><span class="hljs-transposed_variable"><span class="pln">fmt</span><span class="pun">.</span></span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"sum:"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">sum</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"prod:"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">prod</span></span><span class="pun">)</span><span class="pln">
    learnTypes</span><span class="pun">()</span><span class="pln">                           
</span><span class="pun">}</span></code></pre>

<p>
	يمكن أن توجد في تعريف الدوال معاملات وقيم مرجعة متعددة، فمثلا تأخذ الدالة learnMultiple أدناه معاملين x و y وترجع قيمتين sum و prod من نوع عدد صحيح Int.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs axapta"><span class="pln">func learnMultiple</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y </span><span class="hljs-keyword"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">sum</span></span><span class="pun">,</span><span class="pln"> prod </span><span class="hljs-keyword"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// نفصل بين القيم المُرجعة بفاصلة عادية</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> x </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"> y 
</span><span class="pun">}</span></code></pre>

<h2 id="أنواع-البيانات-data-types">
	أنواع البيانات Data Types
</h2>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnTypes</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">//التعريفات القصيرة عادة تؤدي الغرض المطلوب</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// تعريف متغير نصي باستخدام علامة التنصيص المزدوجة   </span></span><span class="pln">
 str </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Learn Go!"</span></span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// تعريف متغير نصي باستخدام علامة التنصيص المنفردة</span></span><span class="pln">
 s2 </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-string"><span class="str">`A "raw" string literal can include line breaks.`</span></span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// تعريف متغير من نوع rune وهو عبارة عن مسمى آخر لنوع int32 ويحتوي المتغير من هذا النوع على يونيكود      </span></span><span class="pln">
g </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Σ'</span></span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// تعريف عدد عشري Float</span></span><span class="pln">
f </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">3.14195</span></span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// تعريف عدد مركب (عقدي)Complex</span></span><span class="pln">
c </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">3</span></span><span class="pln"> </span><span class="pun">+</span><span class="hljs-number"><span class="pln"> </span><span class="lit">4</span></span><span class="lit">i</span><span class="pln">  
</span><span class="hljs-comment"><span class="com">// تعريف المتغيرات باستخدام var</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> u </span><span class="hljs-typename"><span class="kwd">uint</span></span><span class="pln"> </span><span class="pun">=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">7</span></span><span class="pln"> </span><span class="hljs-comment"><span class="com">//عدد طبيعي (صحيح موجب)</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> pi </span><span class="hljs-typename"><span class="pln">float32</span></span><span class="pln"> </span><span class="pun">=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">22</span></span><span class="lit">.</span><span class="pln"> </span><span class="pun">/</span><span class="hljs-number"><span class="pln"> </span><span class="lit">7</span></span><span class="pln"> </span><span class="hljs-comment"><span class="com">//عدد عشري من 32 بت</span></span><span class="pln">

</span><span class="hljs-comment"><span class="com">// طريقة التحويل باستخدام التعريف القصير (byte تعتبر مسمى اخر لنوع uint8)</span></span><span class="pln">
    n </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">byte</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">'\n'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// المصفوفات لها حجم محدد وثابت في وقت الترجمة</span></span><span class="pln">
 </span><span class="hljs-comment"><span class="com">// تعريف مصفوفة من نوع int بحجم 4 عناصر وبقيمة أولية تساوي صفر</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> a4 </span><span class="hljs-number"><span class="pun">[</span><span class="lit">4</span></span><span class="pun">]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pln">

</span><span class="hljs-comment"><span class="com">// تعريف مصفوفة بحجم 3 عناصر بالقيم 3 و 1 و 5 </span></span><span class="pln">
    a3 </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[...]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="hljs-number"><span class="pun">{</span><span class="lit">3</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">1</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">5</span></span><span class="pun">}</span><span class="pln"> </span></code></pre>

<p>
	يقدّم Go نوع بيانات يُسمّى الشرائح Slices. الشرائح (Slices) لها حجم ديناميكي. المصفوفات والشرائح لها مميزات ولكن حالات الاستخدام للشرائح شائعة أكثر.<br>
	تعرّف التعليمة التالية شريحة من النوع int
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-comment"><span class="com">// لاحظ الفرق بين تعريف المصفوفة والشريحة، حيث عند تعريف الشريحة لا يوجد رقم يحدد حجمها</span></span><span class="pln">
    s3 </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="hljs-number"><span class="pun">{</span><span class="lit">4</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">5</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">9</span></span><span class="pun">}</span><span class="pln">    

</span><span class="hljs-comment"><span class="com">//تعريف شريحة من نوع int بأربعة عناصر بقيم صفرية   </span></span><span class="pln">
 s4 </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">([]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">4</span></span><span class="pun">)</span><span class="pln">   

</span><span class="hljs-comment"><span class="com">// تعريف فقط، ولا يوجد تحديد</span></span><span class="pln">
 </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> d2 </span><span class="pun">[][]</span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln">      

 </span><span class="hljs-comment"><span class="com">// طريقة تحويل النوع من نص لشريحة</span></span><span class="pln">
bs </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="hljs-typename"><span class="kwd">byte</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"a slice"</span></span><span class="pun">)</span><span class="pln"> </span></code></pre>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="pln">    s </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="hljs-number"><span class="pun">{</span><span class="lit">1</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">2</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">3</span></span><span class="pun">}</span><span class="pln">     
    s </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">append</span></span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">4</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">5</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">6</span></span><span class="pun">)</span><span class="pln">  
</span><span class="hljs-comment"><span class="com">// ستُطبَع شريحة بالمحتويات التالية [1 2 3 4 5 6]</span></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></code></pre>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs r"><span class="pln">    s </span><span class="pun">=</span><span class="pln"> append</span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[]</span><span class="kwd">int</span><span class="pun">{</span><span class="hljs-number"><span class="lit">7</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">9</span></span><span class="pun">}</span><span class="hljs-keyword"><span class="pun">...</span></span><span class="pun">)</span><span class="pln">  
</span><span class="com">// سيتم طباعة شريحة بالمحتويات التالية [</span><span class="hljs-number"><span class="com">1</span></span><span class="com"> </span><span class="hljs-number"><span class="com">2</span></span><span class="com"> </span><span class="hljs-number"><span class="com">3</span></span><span class="com"> </span><span class="hljs-number"><span class="com">4</span></span><span class="com"> </span><span class="hljs-number"><span class="com">5</span></span><span class="com"> </span><span class="hljs-number"><span class="com">6</span></span><span class="com"> </span><span class="hljs-number"><span class="com">7</span></span><span class="com"> </span><span class="hljs-number"><span class="com">8</span></span><span class="com"> </span><span class="hljs-number"><span class="com">9</span></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="pln">s</span><span class="pun">)</span><span class="pln">  </span></code></pre>

<p>
	تعرّف التعليمة التالية متغيرين p وq ليكونا مؤشّريْن Pointers على متغيّرين من نوع int يحويان قيمتين مُرجعتيْن من الدالة learnMemory:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">    p</span><span class="pun">,</span><span class="pln"> q </span><span class="pun">:</span></span><span class="pun">=</span><span class="hljs-string"><span class="pln"> learnMemory</span><span class="pun">()</span><span class="pln"> </span></span></code></pre>

<p>
	عندما تسبق النجمة مؤشرا فإن ذلك يعني قيمة المتغير الذي يحيل إليه المؤشر، أي في المثال التالي قيمتا المتغيريْن اللذيْن ترجعهما الدالة learnMemory:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs perl"><span class="pln">    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-variable"><span class="pun">*</span><span class="pln">p</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pun">*</span><span class="pln">q</span></span><span class="pun">)</span><span class="pln">   </span></code></pre>

<p>
	الخرائط Maps في Go هي مصفوفات ترابطية يمكن التعديل عليها ديناميكيا وهي تشابه نوع القاموس او الهاش في اللغات الأخرى.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs cpp"><span class="hljs-comment"><span class="com">/* هنا نعرف خريطة يكون مفتاحها من نوع نصي، وقيم العناصر رقمية. */</span></span><span class="pln">
    m </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">map</span></span><span class="pun">[</span><span class="hljs-built_in"><span class="kwd">string</span></span><span class="pun">]</span><span class="hljs-keyword"><span class="kwd">int</span></span><span class="pun">{</span><span class="hljs-string"><span class="str">"three"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"four"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">}</span><span class="pln">
    m</span><span class="pun">[</span><span class="hljs-string"><span class="str">"one"</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span></code></pre>

<p>
	تعدّ لغة Go المتغيرات غير المستخدمة خطأ. التسطير السفلي بالطريقة التالية يجعلك تستخدم المتغير ولكن تتجاهل قيمته في نفس الوقت:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs fix"><span class="hljs-attribute"><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><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><span class="pln"> _</span><span class="pun">,</span><span class="pln"> _ </span></span><span class="pun">=</span><span class="hljs-string"><span class="pln"> str</span><span class="pun">,</span><span class="pln"> s2</span><span class="pun">,</span><span class="pln"> g</span><span class="pun">,</span><span class="pln"> f</span><span class="pun">,</span><span class="pln"> u</span><span class="pun">,</span><span class="pln"> pi</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> a3</span><span class="pun">,</span><span class="pln"> s4</span><span class="pun">,</span><span class="pln"> bs</span></span></code></pre>

<p>
	تُستخدَم هذه الطريقة عادة لتجاهل قيمة راجعة من دالة، فمثلا تستطيع تجاهل رقم الخطأ الراجع من دالة إنشاء الملف os.Create والذي يفيد بأن الملف موجود مسبقا، وتفترض دائما أن الملف شيُنشَأ:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs avrasm"><span class="pln">    file</span><span class="pun">,</span><span class="pln"> _ </span><span class="pun">:=</span><span class="pln"> os</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Create</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"output.txt"</span></span><span class="pun">)</span><span class="pln">
    fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Fprint</span></span><span class="pun">(</span><span class="pln">file</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"بالمناسبة، هذه هي دالة الكتابة في ملف"</span></span><span class="pun">)</span><span class="pln">
    file</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Close</span></span><span class="pun">()</span><span class="pln">

    fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Println</span></span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">,</span><span class="pln"> a4</span><span class="pun">,</span><span class="pln"> s3</span><span class="pun">,</span><span class="pln"> d2</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">)</span><span class="pln">

    learnFlowControl</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="القيم-الراجعة-المسماة-named-return-values">
	القيم الراجعة المسماة Named return values
</h2>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnNamedReturns</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">z </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    z </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">*</span><span class="pln"> y
</span><span class="hljs-comment"><span class="com">//هنا كتبنا كلمة return فقط وضمنيا نعني إعادة قيمة المتغير z</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> 
</span><span class="pun">}</span></code></pre>

<p>
	<strong>ملاحظة:</strong> تعتمد لغة Go كثيرا على جمع الموارد غير المستخدمة Garbage collection. توجد في Go مؤشّرات لكن بدون إجراء عمليات حسابية عليها (تستطيع الخطأ في استخدام مؤشر فارغ ولكن لا تستطيع الزيادة على المؤشر).
</p>

<h2 id="المتغيرات-والذاكرة">
	المتغيرات والذاكرة
</h2>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnMemory</span><span class="pun">()</span><span class="pln"> </span><span class="pun">(</span><span class="pln">p</span><span class="pun">,</span><span class="pln"> q </span><span class="pun">*</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    p </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">new</span></span><span class="pun">(</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> 
</span><span class="hljs-comment"><span class="com">// تعريف شريحة من 20 عنصر كوحدة واحدة في الذاكرة</span></span><span class="pln">
s </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">([]</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">20</span></span><span class="pun">)</span><span class="pln">

</span><span class="hljs-comment"><span class="com">// إعطاء قيمة لأحد العناصر</span></span><span class="pln">
s</span><span class="hljs-number"><span class="pun">[</span><span class="lit">3</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">7</span></span><span class="pln">             
</span><span class="hljs-comment"><span class="com">// تعريف متغير جديد محلي على مستوى الدالة</span></span><span class="pln">
r </span><span class="pun">:=</span><span class="hljs-number"><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span></span><span class="pln">              
</span><span class="hljs-comment"><span class="com">// إرجاع قيمتين من الدالة هما عبارة عن عناوين الذاكرة للمتغيرات s و r على الترتيب.</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="hljs-number"><span class="pun">[</span><span class="lit">3</span></span><span class="pun">],</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">r     
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> expensiveComputation</span><span class="pun">()</span><span class="pln"> </span><span class="hljs-typename"><span class="pln">float64</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> m</span><span class="pun">.</span><span class="typ">Exp</span><span class="hljs-number"><span class="pun">(</span><span class="lit">10</span></span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="جمل-التحكم">
	جمل التحكم
</h2>

<p>
	تتطلّب الجمل الشرطية وجود أقواس مزخرفة ولا تتطلب وجود أقواس هلالية.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnFlowControl</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">true</span></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="hljs-string"><span class="str">"told ya"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">false</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-comment"><span class="com">// Pout.</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-comment"><span class="com">// Gloat.</span></span><span class="pln">
    </span><span class="pun">}</span></code></pre>

<p>
	نستخدم جملة <code>switch</code> في حال حاجتنا لكتابة أكثر من جملة شرطية متتابعة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs cs"><span class="pln">    x </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">42.0</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">switch</span></span><span class="pln"> x </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">:</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">:</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">42</span></span><span class="pun">:</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">43</span></span><span class="pun">:</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">default</span></span><span class="pun">:</span><span class="pln">        
    </span><span class="pun">}</span></code></pre>

<p>
	كما الجملة الشرطية، فإن جملة <code>for</code> لا تأخذ أقواس هلالية.المتغيرات المعرفة في جملة <code>for</code> تكون مرئية على مستوى الجملة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs bash"><span class="pln">    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> x </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">;</span><span class="pln"> x</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="hljs-string"><span class="str">"iteration"</span></span><span class="pun">,</span><span class="pln"> x</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span></code></pre>

<p>
	جملة for هي جملة التكرار الوحيدة في لغة Go ولها شكل آخر بالطريقة التالية:
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs cs"><span class="pln">    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="hljs-comment"><span class="com">// تكرار لا نهائي  </span></span><span class="pln">
 </span><span class="hljs-comment"><span class="com">// نستطيع استخدام break لوقف التكرار</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">break</span></span><span class="pln">    
</span><span class="hljs-comment"><span class="com">// نستطيع استخدام continue للذهاب للتكرار القادم</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">continue</span></span><span class="pln"> 
    </span><span class="pun">}</span></code></pre>

<p>
	تستطيع استخدام range للمرور على عناصر مصفوفة، شريحة، نص، خريطة أو قناة <code>Channel</code> تـعيد <code>range</code> قيمة واحدة عند استخدام قناة، وقيمتين عند استخدام شريحة أو مصفوفة أو نص أو خريطة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs cs"><span class="hljs-comment"><span class="com">// مثال:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">value</span></span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> range map</span><span class="pun">[</span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pun">]</span><span class="hljs-keyword"><span class="kwd">int</span></span><span class="pun">{</span><span class="hljs-string"><span class="str">"one"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"two"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"three"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// نطبع قيمة كل عنصر في الخريطة</span></span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Printf</span><span class="pun">(</span><span class="hljs-string"><span class="str">"key=%s, value=%d\n"</span></span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">value</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span></code></pre>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs applescript"><span class="pln">    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-property"><span class="pln">name</span></span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> range </span><span class="pun">[]</span><span class="hljs-type"><span class="kwd">string</span></span><span class="pun">{</span><span class="hljs-string"><span class="str">"Bob"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Bill"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"Joe"</span></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="hljs-string"><span class="str">"Hello, %s\n"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-property"><span class="pln">name</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span></code></pre>

<p>
	نستطيع استخدام التعريف القصير مع الجملة الشرطية بحيث يُعرف متغير ومن ثم يُفحَص في جملة الشرط.<br>
	نعرّف في ما يلي متغيرًا y ونقوم بإعطائه قيمة ومن ثم نقوم بوضع شرط الجملة بحيث يتم فصلهما ب فاصلة منقوطة.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs matlab"><span class="pln">    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> y </span><span class="pun">:=</span><span class="pln"> expensiveComputation</span><span class="pun">();</span><span class="pln"> y </span><span class="pun">&gt;</span><span class="pln"> x </span><span class="hljs-cell"><span class="pun">{</span><span class="pln">
        x </span><span class="pun">=</span><span class="pln"> y
    </span><span class="pun">}</span></span></code></pre>

<p>
	نستطيع تعريف دوال وهمية <code>anonymous</code> مباشرة في الشفرة البرمجية”
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="pln">    xBig </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">()</span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">bool</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// عرّفنا المتغيّر x التالي قبل جملة switch السابقة</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> x </span><span class="pun">&gt;</span><span class="hljs-number"><span class="pln"> </span><span class="lit">10000</span></span><span class="pln"> 
    </span><span class="pun">}</span><span class="pln">
    x </span><span class="pun">=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">99999</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// ترجع الدالة xBig الآن القيمة true</span></span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"xBig:"</span></span><span class="pun">,</span><span class="pln"> xBig</span><span class="pun">())</span><span class="pln"> 
    x </span><span class="pun">=</span><span class="hljs-number"><span class="pln"> </span><span class="lit">1.3e3</span></span><span class="pln">                    
</span><span class="hljs-comment"><span class="com">// بعد تعديل قيمة x إلى 1.3e3 التي تساوي 1300 (أي أكبر من 1000) فإن الدالة xBig ترجع false</span></span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"xBig:"</span></span><span class="pun">,</span><span class="pln"> xBig</span><span class="pun">())</span><span class="pln"> </span></code></pre>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="pln">    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"Add + double two numbers: "</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </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"> </span><span class="pun">*</span><span class="hljs-number"><span class="pln"> </span><span class="lit">2</span></span><span class="pln">
        </span><span class="pun">}</span><span class="hljs-number"><span class="pun">(</span><span class="lit">10</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">2</span></span><span class="pun">))</span><span class="pln">    
    </span><span class="hljs-keyword"><span class="kwd">goto</span></span><span class="pln"> love
love</span><span class="pun">:</span><span class="pln">

    learnFunctionFactory</span><span class="pun">()</span><span class="pln"> </span><span class="hljs-comment"><span class="com">// دالة ترجع دالة</span></span><span class="pln">
    learnDefer</span><span class="pun">()</span><span class="pln">      </span><span class="hljs-comment"><span class="com">// التأجيل</span></span><span class="pln">
    learnInterfaces</span><span class="pun">()</span><span class="pln"> </span><span class="hljs-comment"><span class="com">// التعامل مع الواجهات</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="توليد-الدوال">
	توليد الدوال
</h2>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs mizar"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnFunctionFactory</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></code></pre>

<p>
	تعدّ الطريقتان التاليتان في طباعة الجملة متماثلتين، إلا أن الطريقة الثانية أوضح ومقروءة أكثر وهي الشائعة.
</p>

<pre class="ipsCode" id="ips_uid_2511_9">
    fmt.Println(sentenceFactory("summer")("A beautiful", "day!"))

    d := sentenceFactory("summer")
    fmt.Println(d("A beautiful", "day!"))
    fmt.Println(d("A lazy", "afternoon!"))
}</pre>

<p>
	المزخرفات Decorators موجودة في بعض لغات البرمجة، وموجودة بنفس المفهوم في لغة Go بحيث نستطيع تمرير معطيات إلى الدوال.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs livecodeserver"><span class="pln">func sentenceFactory</span><span class="pun">(</span><span class="pln">mystring </span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> func</span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">before</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">after</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-constant"><span class="kwd">return</span></span><span class="pln"> func</span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">before</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">after</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">string</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-constant"><span class="kwd">return</span></span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Sprintf</span><span class="pun">(</span><span class="hljs-string"><span class="str">"%s %s %s"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">before</span></span><span class="pun">,</span><span class="pln"> mystring</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">after</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="التنفيذ-المؤجل">
	التنفيذ المؤجل
</h2>

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

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnDefer</span><span class="pun">()</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ok </span><span class="hljs-typename"><span class="kwd">bool</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// تُنفَّذ التعليمات المؤجلة قبل أن ترجع الوظيفة  النتيجة.   </span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"deferred statements execute in reverse (LIFO) order."</span></span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">defer</span></span><span class="pln"> fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"\nThis line is being printed first because"</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// يُستخدَم تأجيل التنفيذ عادة لإغلاق ملف بعد فتحه.</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">true</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="الواجهات-interfaces">
	الواجهات Interfaces
</h2>

<p>
	نعرّف في ما يلي دالة باسم <code>Stringer</code> تحتوي على دالة واحدة باسم <code>String</code> ؛ ثم نعرّف هيكلا <code>Struct</code> من خانتين نوع int باسم x وy.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs haskell"><span class="hljs-typedef"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> </span><span class="hljs-type"><span class="typ">Stringer</span></span><span class="pln"> </span><span class="kwd">interface</span><span class="pln"> </span><span class="hljs-container"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-type"><span class="typ">String</span></span><span class="pun">()</span><span class="pln"> </span><span class="hljs-title"><span class="kwd">string</span></span><span class="pln">
</span><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-typedef"><span class="hljs-keyword"><span class="pln">type</span></span><span class="pln"> pair </span><span class="kwd">struct</span><span class="pln"> </span><span class="hljs-container"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-title"><span class="pln">x</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-title"><span class="pln">y</span></span><span class="pln"> </span><span class="hljs-title"><span class="kwd">int</span></span><span class="pln">
</span><span class="pun">}</span></span></span></code></pre>

<p>
	نعرّف في ما يلي دالة <code>String</code> على النوع pair، ليصبح pair تطبيقا Implementation للواجهة <code>Stringer</code>. يُسمى المتغيّرp أدناه بالمُستقبل. لاحظ كيفية الوصول لحقول الهيكل pair وذلك باستخدام اسم الهيكل متبوعا بنقطة ثم اسم الحقل.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs lasso"><span class="pln">func </span><span class="pun">(</span><span class="pln">p </span><span class="hljs-built_in"><span class="pln">pair</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-built_in"><span class="typ">String</span></span><span class="pun">()</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">string</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> fmt</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="typ">Sprintf</span><span class="pun">(</span><span class="hljs-string"><span class="str">"(%d, %d)"</span></span><span class="pun">,</span><span class="pln"> p</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">x</span><span class="pun">,</span><span class="pln"> p</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">y</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	تُستخدَم الأقواس الهلالية لإنشاء عنصر من الهياكل <code>Structs</code>. نستخدم التعريف القصير (باستخدام := ) في المثال أدناه لإنشاء متغير باسم p وتحديد نوعه بالهيكل pair .
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs lasso"><span class="pln">func learnInterfaces</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    p </span><span class="hljs-subst"><span class="pun">:=</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">pair</span></span><span class="pun">{</span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">}</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// نستدعي الدالة String الخاصة بالنوع pair     </span></span><span class="pln">
fmt</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="typ">Println</span><span class="pun">(</span><span class="pln">p</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="hljs-built_in"><span class="typ">String</span></span><span class="pun">())</span><span class="pln"> 
</span><span class="hljs-comment"><span class="com">// نُعرف متغيرًا باسم i من نوع الواجهة المعرفة سابقا Stringer</span></span><span class="pln">
</span><span class="hljs-built_in"><span class="kwd">var</span></span><span class="pln"> i </span><span class="typ">Stringer</span><span class="pln">          
</span><span class="hljs-comment"><span class="com">// هذه المساواة صحيحة، لأن pair تُطبق Stringer</span></span><span class="pln">
i </span><span class="hljs-subst"><span class="pun">=</span></span><span class="pln"> p                   
</span><span class="hljs-comment"><span class="com">/* نستدعي الدالة String الخاصة بالمتغير i من نوع Stringer ونحصُل على نفس النتيجة السابقة */</span></span><span class="pln">
fmt</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="hljs-built_in"><span class="typ">String</span></span><span class="pun">())</span><span class="pln">

</span><span class="hljs-comment"><span class="com">/* عند تمرير المتغيرات السابقة مباشرةإلى دوال الحزمة fmt الخاصة بالطباعة والإخراج، فإن هذه الدوال تستدعي الدالة String لطباعة التمثيل الخاص بالمتغير.  */</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// يعطي السطران التاليان نفس النتيجة السابقة للطباعة   </span></span><span class="pln">
 fmt</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="typ">Println</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln"> 
 fmt</span><span class="hljs-built_in"><span class="pun">.</span></span><span class="typ">Println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> 
    learnVariadicParams</span><span class="pun">(</span><span class="hljs-string"><span class="str">"great"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"learning"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"here!"</span></span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="المدخلات-المتعددة">
	المدخلات المتعددة
</h2>

<p>
	من الممكن أن نمرر معطيات متغيرة العدد للدوال.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs avrasm"><span class="pln">func learnVariadicParams</span><span class="pun">(</span><span class="pln">myStrings </span><span class="pun">..</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">interface</span></span><span class="pun">{})</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">/* تمرّ جملة التكرار التالية على عناصر المعطيات المدخلة للدالة. التسطير السفلي هنا نعني به تجاهل المؤشر الخاص بالعنصر الذي نمر عليه. */</span></span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> _</span><span class="pun">,</span><span class="pln"> param </span><span class="pun">:=</span><span class="pln"> range myStrings </span><span class="pun">{</span><span class="pln">
        fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Println</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"param:"</span></span><span class="pun">,</span><span class="pln"> param</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="hljs-comment"><span class="com">/* هنا نمرّر مدخلات الدالة ذات العدد المتغير كمعامل لدالة أخرى (للدالة Sprintln) */</span></span><span class="pln">
fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Println</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"params:"</span></span><span class="pun">,</span><span class="pln"> fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Sprintln</span></span><span class="pun">(</span><span class="pln">myStrings</span><span class="pun">...))</span><span class="pln">

    learnErrorHandling</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="معالجة-الأخطاء-errors-handling">
	معالجة الأخطاء Errors Handling
</h2>

<p>
	تُستخدَم الكلمة المفتاحية “ok,” لمعرفة صحة عبارة من عدمها. في حال حدوث خطأ فيمكننا استخدام <code>err</code> لمعرفة تفاصيل أكثر عن الخطأ.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnErrorHandling</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="hljs-keyword"><span class="pln">map</span></span><span class="pun">[</span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">]</span><span class="hljs-typename"><span class="kwd">string</span></span><span class="hljs-number"><span class="pun">{</span><span class="lit">3</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"three"</span></span><span class="pun">,</span><span class="hljs-number"><span class="pln"> </span><span class="lit">4</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"four"</span></span><span class="pun">}</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> ok </span><span class="pun">:=</span><span class="pln"> m</span><span class="hljs-number"><span class="pun">[</span><span class="lit">1</span></span><span class="pun">];</span><span class="pln"> </span><span class="pun">!</span><span class="pln">ok </span><span class="pun">{</span><span class="pln"> 
</span><span class="hljs-comment"><span class="com">// ok هنا ستكون false لأن رقم 1 غير موجود في الخريطة m</span></span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="hljs-string"><span class="str">"no one there"</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// x ستكون القيمة الموجودة في map</span></span><span class="pln">
        fmt</span><span class="pun">.</span><span class="typ">Print</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-comment"><span class="com">/* هنا نحاول أن نقوم بعمل تحويل لقيمة نصية إلى عدد مما سينتج عنه خطأ, ونقوم بطباعة تفاصيل الخطأ في حالة أن err ليست nil */</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> _</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="hljs-string"><span class="str">"non-int"</span></span><span class="pun">);</span><span class="pln"> err </span><span class="pun">!=</span><span class="pln"> </span><span class="hljs-constant"><span class="kwd">nil</span></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="pun">}</span><span class="pln">
    learnConcurrency</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// المعطى c هنا من نوع قناة، وهو كائن لتأمين الاتصالات المتزامنة</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> inc</span><span class="pun">(</span><span class="pln">i </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">,</span><span class="pln"> c </span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// عندما يظهر عنصر من نوع قناة على الشمال، فإن العملية  &lt;- تعني إرسال</span></span><span class="pln">
    c </span><span class="pun">&lt;-</span><span class="pln"> i </span><span class="pun">+</span><span class="hljs-number"><span class="pln"> </span><span class="lit">1</span></span><span class="pln"> 
</span><span class="pun">}</span></code></pre>

<h2 id="التنفيذ-المتزامن-concurrency">
	التنفيذ المتزامن Concurrency
</h2>

<p>
	نستخدم الدالة السابقة لعمل إضافة عددية على بعض الأرقام بالتزامن. نستخدم <code>make</code> كما فعلنا في بداية المقال لإنشاء متغير دون تحديد قيمة له.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs go"><span class="hljs-keyword"><span class="pln">func</span></span><span class="pln"> learnConcurrency</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// هنا نقوم بإنشاء متغير من نوع قناة وباسم c</span></span><span class="pln">
    c </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">int</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">/* نبدأ بإنشاء ثلاثة دوال متزامنة للغة Go. الأعداد سيتم الزيادة عليهابالتزامن (وبالتوازي في حال كان الجهاز مُهيئاً لذلك). */</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// كافة الإرسالات ستتجه لنفس القناة </span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">// كلمة go هنا تعني بدء دالة أو وظيفة جديدة</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> inc</span><span class="hljs-number"><span class="pun">(</span><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln"> 
    </span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> inc</span><span class="hljs-number"><span class="pun">(</span><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> inc</span><span class="hljs-number"><span class="pun">(-</span><span class="lit">805</span></span><span class="pun">,</span><span class="pln"> c</span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// ثم نقوم بعمل ثلاثة قراءات من نفس القناة وطباعة النتائج.</span></span><span class="pln">
</span><span class="hljs-comment"><span class="com">/* لاحظ أنه لا يوجد تحديد ترتيب لوصول القراءات من القناة، ولاحظ أيضا أنه عند ظهور القناة على يمين العملية  &lt;-  فهذا يعني أننا نقوم بقراءة واستقبال من القناة. */</span></span><span class="pln">  
  fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(&lt;-</span><span class="pln">c</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">c</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// قناة جديدة تحتوي على نص</span></span><span class="pln">
cs </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln">       
</span><span class="hljs-comment"><span class="com">// قناة تحتوي على قنوات نصية</span></span><span class="pln">
ccs </span><span class="pun">:=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">make</span></span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">chan</span></span><span class="pln"> </span><span class="hljs-typename"><span class="kwd">string</span></span><span class="pun">)</span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">// إرسال قيمة 84 إلى القناة c</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> c </span><span class="pun">&lt;-</span><span class="hljs-number"><span class="pln"> </span><span class="lit">84</span></span><span class="pln"> </span><span class="pun">}()</span><span class="pln">       
</span><span class="hljs-comment"><span class="com">// إرسال كلمة wordy للقناة cs</span></span><span class="pln">
</span><span class="hljs-keyword"><span class="pln">go</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">func</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> cs </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="hljs-string"><span class="str">"wordy"</span></span><span class="pln"> </span><span class="pun">}()</span><span class="pln"> 

</span><span class="hljs-comment"><span class="com">/* جملة Select تشبه جملة switch ولكنها في كل حالة تحتوي على عملية خاصة بقناة جاهزة للتواصل معها. */</span></span><span class="pln"> 
 </span><span class="hljs-keyword"><span class="kwd">select</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// القيمة المُستلمة من القناة من الممكن أن تُحفظ في متغير.</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">&lt;-</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="hljs-string"><span class="str">"it's a %T"</span></span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">cs</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="hljs-string"><span class="str">"it's a string"</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// قناة فارغة ولكنها جاهزة للتواصل   </span></span><span class="pln">
 </span><span class="hljs-keyword"><span class="kwd">case</span></span><span class="pln"> </span><span class="pun">&lt;-</span><span class="pln">ccs</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="hljs-string"><span class="str">"didn't happen."</span></span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="hljs-comment"><span class="com">// برمجة الويب</span></span><span class="pln">
    learnWebProgramming</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h2 id="الويب">
	الويب
</h2>

<p>
	نستطيع بدء خادوم ويب باستخدام دالة واحدة من حزمة http. نمرّر في المعامل الأول للدالة <code>ListenAndServe</code> عنوان TCP للاستماع له، والمعامل الثاني واجهة عبارة عن معالج http.
</p>

<pre class="ipsCode" id="ips_uid_2511_7">
<code class="hljs avrasm"><span class="pln">func learnWebProgramming</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    go func</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"> http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ListenAndServe</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">":8080"</span></span><span class="pun">,</span><span class="pln"> pair</span><span class="pun">{})</span><span class="pln">
</span><span class="com">// نطبع الأخطاء في حال وجودها.        </span><span class="pln">
fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Println</span></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">

    requestServer</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// اجعل pair معالج http وذلك بواسطة تطبيق دالته الوحيدة المسماة ServeHTTP</span><span class="pln">
func </span><span class="pun">(</span><span class="pln">p pair</span><span class="pun">)</span><span class="pln"> </span><span class="typ">ServeHTTP</span><span class="pun">(</span><span class="pln">w http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ResponseWriter</span></span><span class="pun">,</span><span class="pln"> r </span><span class="pun">*</span><span class="pln">http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Request</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// تتبع الدالة Write للحزمة  http</span><span class="hljs-preprocessor"><span class="com">.ResponseWriter</span></span><span class="com"> ونستخدمها لإرجاع رد لطلب http</span><span class="pln">
w</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Write</span></span><span class="pun">([]</span><span class="kwd">byte</span><span class="pun">(</span><span class="hljs-string"><span class="str">"You learned Go in Y minutes!"</span></span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func requestServer</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    resp</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> http</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Get</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"http://localhost:8080"</span></span><span class="pun">)</span><span class="pln">
    fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Println</span></span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
    defer resp</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Body</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Close</span></span><span class="pun">()</span><span class="pln">
    body</span><span class="pun">,</span><span class="pln"> err </span><span class="pun">:=</span><span class="pln"> ioutil</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">ReadAll</span></span><span class="pun">(</span><span class="pln">resp</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Body</span></span><span class="pun">)</span><span class="pln">
    fmt</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Printf</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"\nWebserver said: `%s`"</span></span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">(</span><span class="pln">body</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	ترجمة – بتصرّف – للمقال <a href="https://learnxinyminutes.com/docs/go" rel="external nofollow">Learn X in Y minutes Where X=Go</a>.
</p>
]]></description><guid isPermaLink="false">534</guid><pubDate>Wed, 13 Sep 2017 19:46:28 +0000</pubDate></item><item><title>&#x643;&#x62A;&#x627;&#x628;&#x629; &#x623;&#x648;&#x644; &#x628;&#x631;&#x646;&#x627;&#x645;&#x62C; (&#x648;&#x645;&#x643;&#x62A;&#x628;&#x629;) &#x644;&#x643; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x644;&#x63A;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/golang-3.png.860ffdacac4e80d844d8b9df8c874d1e.png" /></p>

<p>كيف تبدو البرمجة بلغة Go؟ وكيف أقوم بتشغيل برنامج كُتب بـ Go؟ هذا ما سنتعرف عليه خلال هذا الدرس من سلسلة <a href="https://academy.hsoub.com/search/?tags=%D9%85%D8%AF%D8%AE%D9%84+%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">مدخل إلى لغة البرمجة Go</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/">الدرسين</a> <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/">السابقين</a> منها أولا.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/golang-3.png.7da4388ce13a44d1f97f20919aa50fdc.png"><img data-fileid="11364" class="ipsImage ipsImage_thumbnailed" alt="golang-3.thumb.png.5b688518dfa2ec34b351f" src="https://academy.hsoub.com/uploads/monthly_2016_01/golang-3.thumb.png.5b688518dfa2ec34b351f0f2c05f0ea7.png"></a></p><h2>أهلا بالعالم</h2><p>سنحاول اتباع العادة التي جرت عليها دروس تعلم لغات البرمجة، وهي ببساطة كتابة جملة "أهلا بالعالم" (بالانجليزية "Hello World") باللغة المُراد تعلمها، ببساطة هذا ما سيبدو عليه برنامج أهلا بالعالم في Go:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">package main

import "fmt"

func main() {
    fmt.Print("أهلا بالعالم\n")
}</pre><p>ضع هذا في ملف باسم <span style="font-family:courier new,courier,monospace;">helloworld.go</span> داخل مجلد باسم <span style="font-family:courier new,courier,monospace;">hellogo</span> مثلا، تحت مسار:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$GOPATH/src/github.com/<span style="color:#FF0000;">YOUR_USER</span>/</pre><ul><li>حيث<span style="font-family:courier new,courier,monospace;"> GOPATH$</span> هو مسار بيئة عملك، <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/">راجع الدرس الثاني لتفهم آلية عمله.</a></li><li>غيّر <span style="font-family:courier new,courier,monospace;">YOUR_USER</span> إلى اسم مستخدمك على <a rel="external nofollow" href="https://github.com/">github.com</a> مثلا أو أحد خدمات إدارة الشفرة البرمجية.</li></ul><p>بالتالي سيكون المسار النهائي للملف الجديد الذي أنشأناه هو:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$GOPATH/src/github.com/<span style="color:#FF0000;">YOUR_USER</span>/hellogo/helloworld.go</pre><p>كل ما عليك فعله الآن هو التنقل إلى مسار الملف وكتابة أمر <span style="font-family:courier new,courier,monospace;">go run helloworld.go</span></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$ go run helloworld.go
أهلا بالعالم</pre><p>إذا كانت طرفية سطر الأوامر لديك لا تدعم اللغة العربية، فقد تجد أن الكتابة العربية مقلوبة والحروف متقطعة، لا بأس بذلك حاليا، لكن لاحظ أن Go قبلت بالحروف العربية داخل نص الشفرة البرمجية وتعاملت معها بشكل عادي، ذلك لأن كل شيء تعتبره <a rel="external nofollow" href="https://ar.wikipedia.org/wiki/%D9%8A%D9%88%D9%86%D9%8A%D9%83%D9%88%D8%AF">unicode</a> افتراضا.</p><p><strong>لنشرح البرنامج سطرًا بسطر:</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">package main</pre><p>ببساطة:</p><ul><li>لابد لكل ملف شيفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.</li><li>ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.</li><li>لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات)، كما <span style="line-height: 22.4px;">يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.</span></li></ul><p>في مثالنا السابق، أعطينا <span style="font-family:courier new,courier,monospace;">main</span> كاسم لحزمتنا، وهو اسم خاص، حيث يُعامل مُجمّع (compiler) لغة Go هذه الحزمة على أنها مدخل البرنامج (program entry)، أي أن التعليمات الموجودة في هذه الحزمة يتم تشغيلها أولا. أسبقنا اسم الحزمة بالكملة المفتاحية <span style="font-family:courier new,courier,monospace;">package</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">import "fmt"</pre><ul><li><span style="font-family:courier new,courier,monospace;">import</span>: كلمة مفتاحية أخرى وتعني "استرِد" أو "اجلِب" المكتبة الفلانية أو الحزمة الفلانية.</li><li><span style="font-family:courier new,courier,monospace;">"fmt"</span> اختصار لـ format أو formatting وهي مكتبة قياسية (standard library) تأتي مع تنصيب Go، خاصة ببناء وطباعة النص. لاحظ أن اسم المكتبات أو الحزم المُراد استيرادها دائما ما يتم إحاطتها بعلامة اقتباس <span style="font-family:courier new,courier,monospace;">""</span>.</li></ul><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">func main() {</pre><p>هنا قمنا بإنشاء دالة تحمل اسم main:</p><ul><li>لإنشاء الدالة استعملنا الكملة المفتاحية <span style="font-family:courier new,courier,monospace;">func</span> ثم مسافة، ثم اسم الدالة.</li><li>مثل <strong>حزمة</strong> <span style="font-family:courier new,courier,monospace;">main</span> فإن <strong>دالة</strong> <span style="font-family:courier new,courier,monospace;">main</span> أيضا يعاملها المجمع (Compiler) معاملة خاصة، حيث تعتبر هي نقطة دخول البرنامج (Entry point)، أي أن التعليمات الموجودة في هذه الدالة تحديدا، داخل حزمة <span style="font-family:courier new,courier,monospace;">main</span> تحديدًا، يتم تشغيلها أولا، إلا في حالة وجود دالة أخرى باسم <span style="font-family:courier new,courier,monospace;">()init</span> والتي سنتعرض لها في دروس أخرى.</li><li>مثل جافاسكريبت وباقي اللغات، فإن <strong><span style="font-family:courier new,courier,monospace;">}</span></strong> يفتح جسم الدالة (function body).</li></ul><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">fmt.Print("أهلا بالعالم\n")</pre><ul><li>هنا قمنا باستعمال حزمة "<span style="font-family:courier new,courier,monospace;">fmt</span>" التي قمنا باستيرادها أعلاه، لاستعمال أي حزمة في Go يكفي كتابة اسمها، ثم نقطة، ثم اسم الدالة التي تريدها استعمالها من تلك الحزمة، في حالتنا هذه، أردنا ببساطة طباعة نص "أهلا بالعالم" والرجوع إلى السطر، لذلك استعملنا دالة <span style="font-family:courier new,courier,monospace;">Print</span> ومررلنا لها القيمة "n\أهلا بالعالم":</li><li>مررنا القيمة بين علامتي اقتباس <span style="font-family:courier new,courier,monospace;">""</span> ﻷنها عبارة عن سلسلة نصية (<span style="font-family:courier new,courier,monospace;">string</span>).</li><li>أنهينا سلسلتنا النصية بعلامة <strong><span style="font-family:courier new,courier,monospace;">n\</span></strong> وهي علامة خاصة في أغلب لغات البرمجة، وتعني "سطر جديد"، استعملناها للرجوع إلى السطر.</li><li>نُمرّر القيم والمعاملات للداوال عبر وضعها بين قوسين مباشرة بجنب اسم الدالة.</li></ul><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">}</pre><ul><li>أغلقنا جسم الدالة main باستعمال علامة <strong><span style="font-family:courier new,courier,monospace;">{</span></strong>، أي أن تعليمات هذه الدالة قد انتهت.</li><li>لاحظ غياب علامة الفاصلة المنقوطة "<span style="font-family:courier new,courier,monospace;"><strong>;</strong></span>" بعد نهاية كل تعليمة، لا حاجة لها في Go.</li></ul><h2>مفهوم الحزم (Packages) في Go</h2><p>الحزم (packages) طريقة بسيطة لتجزئة برنامجك إلى أجزاء أصغر مُقسّمة حسب الغرض أو الوظيفة، يُمكن الاشارة للحزم على أنهم "مكتبات" (libraries) أو وحدات (modules)، تركيب الحزم مع بعضها يشكل مُجمل برنامجك.</p><p>تتبع Go القواعد التالية في كيفية تقسيم برنامج إلى حزم:</p><ul><li>الحزمة غالبا عبارة عن مجلد داخل مشروعك به الملفات التي تحمل اسم الحزمة.</li><li>لابد من وجود حزمة واحدة على الأقل في أي برنامج أو مكتبة.</li><li>إذا كان البرنامج عبارة عن برنامج تنفيذي (وليس مكتبة - library) فإنه يجب وجود حزمة باسم <span style="font-family:courier new,courier,monospace;">main</span> (أي <span style="font-family:courier new,courier,monospace;">package main</span>) تكون هي مدخل البرنامج كما رأيناه في مثالنا الأول.</li></ul><p>وكتذكير لما ذكرناه سابقا:</p><ul><li>لابد لكل ملف شفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.</li><li>ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.</li><li>لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات).</li><li>يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.</li><li>يمكن للمجلد الرئيسي لمشروعك أن يحتوي على حزمة ما، <strong>واحدة فقط</strong>، باقي الحزم الخاصة به يمكنها أن تتواجد في مجلدات فرعية.</li><li>غياب حزمة <span style="font-family:courier new,courier,monospace;">main</span> من برنامج ما، يجعل منه <strong>مكتبة فقط</strong> وليس برنامجا تشغيليا قائما بحد ذاته.</li></ul><p>عند كتابة الحزم، أي اسم دالة أو متغير أو بُنية (Struct) يبدأ بحرف كبير (Uppercase) يعني أن هذه الدالة/المتغير/البنية متوفر بشكل عام لجميع من يقوم باستيراد هذه الحزمة عبر الكلمة المفتاحية <span style="font-family:courier new,courier,monospace;">import</span>. وأي اسم دالة/متغير يبدأ بحالة أحرف صغيرة (Lowercase) يعني أنه خاص ولن يتم تصديره (لن يكون متاحا) لباقي الحزم والبرامج.</p><p>في مثالنا السابق، وفّرت حزمة "<span style="font-family:courier new,courier,monospace;">fmt</span>" دالة <span style="font-family:courier new,courier,monospace;">Print</span> لنا بشكل مُتاح، لاحظ أن <span style="font-family:courier new,courier,monospace;">Print</span> تبدأ بحرف <strong><span style="font-family:courier new,courier,monospace;">P </span></strong>كبير (Uppercase). وكان فقط يكفي كتابة <span style="font-family:courier new,courier,monospace;"><span style="line-height: 22.4px;">(...)</span>fmt.Print</span></p><h2>مكتبة (حزمة) أهلا بالعالم</h2><p>ماذا لو أردنا قول "أهلا بالعالم" في أكثر من مشروع؟ ربما سيكون من الأمثل جعل طباعة "أهلا بالعالم" في مكتبة مستقلة نقوم باستيرادها في مشاريع أخرى، هذا مثال فقط لكيفية بناء مكتبة في Go، فطبعا لن تحتاج إلى مكتبة كل ما تقوم به هو "أهلا بالعالم".</p><p>دعنا نحاول كتابة هذا في دالة بسيطة، نسميها <span style="font-family:courier new,courier,monospace;">SayHello</span> ولنضها في حزمة خاصة، نسميها <span style="font-family:courier new,courier,monospace;">sayhello</span>.</p><p>دعنا نبني هذه المكتبة في مشروع مستقل، لتكون مكتبة يُمكن جلبها في أكثر من برنامج أو مشروع آخر. سنسمي المشروع <font face="courier new, courier, monospace">sayhello</font>، أي بنفس اسم الحزمة لتسهيل الأمر. لن نحتاج إلى <span style="font-family:courier new,courier,monospace;">package main </span>ﻷننا سنبني مكتبة فقط وليس برنامجا تنفيذيا في حد ذاته.</p><p>بالتالي قم بإنشاء مجلد مشروع جديد تحت مسار:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$GOPATH/src/github.com/YOUR_USER/</pre><p>بنفس الطريقة التي شرحناها سابقا.</p><p>أنشئ ملفا باسم <span style="font-family:courier new,courier,monospace;">sayhello.go</span> تحت مجلد <span style="font-family:courier new,courier,monospace;">sayhello</span>، ليكون مسار الملف أشبه بهذا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$GOPATH/src/github.com/YOUR_USER/sayhelo/sayhello.go</pre><p>والآن، نفتح ملف <span style="font-family:courier new,courier,monospace;">sayhello.go</span> بمحرر النصوص المفضل لديك ثم نشرع في كتابة دالتنا المذهلة، لا يُفترض بك فهم كل شيء حاليا، فالغرض شرح مفهوم الحزم والمكتبات، مع ذلك سنحاول شرح تعليمات هذه الدالة:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">package sayhello

// SayHello returns Hello World in Arabic.
func SayHello() string {
    return "أهلا بالعالم\n"
}
</pre><p>لاحظ أن دالتنا لا تختلف كثيرًا عن برنامج "أهلا بالعالم" الذي كتبناه أول مرة:</p><ul><li>استعملنا<span style="font-family:courier new,courier,monospace;"> package sayhello</span> عوض<span style="font-family:courier new,courier,monospace;"> package main.</span></li><li>سمينا الدالة<span style="font-family:courier new,courier,monospace;"> ()func SayHello</span> عوض <span style="font-family:courier new,courier,monospace;">()func main</span>. لاحظ أننا جعلنا اسم الدالة يبدأ بحرف كبير (Uppercase) ذلك ﻷننا نريد تصدير هذه الدالة وإتاحتها لباقي المشاريع التي تسترد حزمة sayhello.</li><li>قمنا بتصريح أن الدالة تُرجع سلسلة نصية عبر كتابة الكلمة المفتاحية <span style="font-family:courier new,courier,monospace;">string</span> على يمين الدالة.</li><li>قمنا بإرجاع السلسلة النصية "n\أهلا بالعالم" عبر الكلمة المفتاحية <span style="font-family:courier new,courier,monospace;">return</span> عوض طباعتها باستخدام مكتبة <span style="font-family:courier new,courier,monospace;">fmt</span> كما فعلنا أول مرة.</li></ul><p>أصبح الآن لدينا "أهلا بالعالم" في شكل مكتبة! لكن كيف نجعلها قابلة للجلب؟ أي كيف نضعها في مجلد <span style="font-family:courier new,courier,monospace;">pkg</span> حتى تستطيع باقي المشاريع جلبها والاستفادة منها؟</p><p>كل ما علينا فعله هو كتابة <span style="font-family:courier new,courier,monospace;">go install</span> داخل مجلد مشروع <span style="font-family:courier new,courier,monospace;">sayhello</span>. </p><p>طبعا لن يكون بإمكانك تشغيل هذه المكتبة عبر أمر <span style="font-family:courier new,courier,monospace;">go run sayhello.go</span> مثل ما فعلنا أو مرّة، ﻷن ما قمنا بكتابته هذه المرة عبارة عن مكتبة وليس برنامجًا تنفيذيًا!</p><h2>فحص مكتبة "أهلا بالعالم"</h2><p>هل تعمل دالتنا بشكل جيد؟ كيف يمكن التحقق من برامجنا وحزمنا التي نكتبها في Go؟ هل مكتبة "أهلا بالعالم" تطبع حقا "أهلا بالعالم"؟ دعنا نتأكد من ذلك عبر كتابة فحص مؤتمت لهذه الدالة!</p><p>في لغة Go:</p><ul><li>يمكن كتابة فحوصات واختبار وحدات (Unit testing) بسهولة، يكفي إنشاء ملف بنفس اسم الملف المُراد اختباره مع إضافة <span style="font-family:courier new,courier,monospace;">test_</span> له.</li><li>يمكن فحص دالة معينة بمجرد كتابة Test ثم اسم الدالة.</li></ul><p>في حالتنا هذه، وفي نفس مسار مشروع <span style="font-family:courier new,courier,monospace;">sayhello</span> أنشئ ملفا باسم <span style="font-family:courier new,courier,monospace;">sayhello_test.go</span> بجانب ملف <span style="font-family:courier new,courier,monospace;">sayhello.go</span> نفسه لنقوم باختبار حزمة <span style="font-family:courier new,courier,monospace;">sayhello</span>.</p><p>افتح ملف sayhello_test.go بمحرر النصوص المفضل لديك. كل ما علينا فعله لتجربة دالتنا هو جلبها وفحص إذا كانت نتيجة الطباعة هي فعلا "أهلا بالعالم"! كما هو موضح في الشفرة التالية:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">package sayhello

import "testing"

func TestSayHello(t *testing.T) {
    greeting := SayHello()
    if greeting != "أهلا بالعالم\n" {
        t.Error("TEST FAILED!")
    }
}
</pre><p>في الشِيفرة أعلاه:</p><ul><li>قمنا باستيراد حزمة "<span style="font-family:courier new,courier,monospace;">testing</span>" القياسية التي توفرها لغة Go بشكل افتراضي لأغراض إنشاء الفحوصات المؤتمتة.</li><li>بما أننا نريد فحص دالة <span style="font-family:courier new,courier,monospace;">SayHello</span> قمنا بإنشاء دالة <span style="font-family:courier new,courier,monospace;">TestSayHello</span> مع تمرير <span style="font-family:courier new,courier,monospace;">testing.T</span> لها، أي أن هذه الدالة تُعتبر "حالة فحص"، لا يجب عليك فهم هذا التعبير حاليا، يمكنك تجاهله، الغرض هو فهم آلية عمل الفحوصات المؤتمتة في Go.</li></ul><p>داخل هذه الدالة الفاحصة، قمنا ببساطة بنداء دالتنا <span style="font-family:courier new,courier,monospace;">SayHello</span> وفحص إذا كانت القيمة التي تُرجعها عبارة عن "n\أهلا بالعالم" فإن كانت كذلك، يمر الفحص بسلام ولن نطبع أي شيء، وإن لم تكن كذلك، نطبع "!TEST FAILED" باستخدام المعامل t التابع لحزمة <span style="font-family:courier new,courier,monospace;">testing</span> القياسية باستعمال الدالة <span style="font-family:courier new,courier,monospace;">Error</span>، والتي تُخبر بدورها أن حالة الفحص هذه قد فشلت.</p><p>الآن، في نفس المجلد الذي أنت به يكفي كتابة <span style="font-family:courier new,courier,monospace;"><strong>go test</strong></span> لفحص حزمة <span style="font-family:courier new,courier,monospace;">sayhello</span> الخاص بنا! يُفترض أن تتلقى نتيجة مشابهة لهذه:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">PASS
ok  	github.com/01walid/sayhello	0.001s</pre><p>يمكن إضافة <span style="font-family:courier new,courier,monospace;"><strong>v-</strong></span> أو <span style="font-family:courier new,courier,monospace;"><strong>cover--</strong></span> إلى الأمر السابق لطباعة المزيد من المعلومات حول الفحوصات التي يقوم بها المُجمع، مثلا <strong><span style="font-family:courier new,courier,monospace;">go test -v --cover</span></strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">=== RUN   TestSayHello
--- PASS: TestSayHello (0.00s)
PASS
coverage: 100.0% of statements
ok  	github.com/01walid/sayhello	0.001s
</pre><p>لاحظ أننا تحصلنا على coverage: 100.0%! أي أن الفحوص التي قمنا بها تغطي جميع الدوال التي قمنا بكتابتها في هذا المشروع (بما أن لدينا دالة واحدة فقط وفحص واحد، فالنتيجة طبيعية)، من المستحسن دائما إبقاء نسبة تغطية الفحوصات مرتفعة في برامجك، حتى تضمن أن استقرارها جيد ويمكن التعويل عليها.</p><h2>إنشاء توثيق لمكتبة "أهلا بالعالم"</h2><p>أنهينا مكتبتنا المذهلة، تأكدنا من صحة عملها، ماذا لو أمكننا توليد ومشاركة توثيق لها؟ لن تحتاج الكثير لفعل ذلك!</p><p>كل ما عليك فعله هو كتابة الأمر  <strong><span style="font-family:courier new,courier,monospace;">godoc -http=:6060</span></strong> ثم زيارة<span style="font-family:courier new,courier,monospace;"> localhost:6060</span> على متصفحك! ستحتاج إلى التنقل إلى توثيق مكتبتك بشكل خاص عبر زيادة </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">http://localhost:6060/pkg/github.com/YOUR_USER/sayhello/</pre><p>طبعا قم بتغيير <span style="font-family:courier new,courier,monospace;">YOUR_USER</span> إلى اسم المستخدم الخاص بك، تماما مثل مسار المكتبة في بيئة <span style="font-family:courier new,courier,monospace;">GOPATH$</span> الخاص بك.</p><h2>استعمال مكتبة "أهلا بالعالم"</h2><p>دعنا نستعمل هذه المكتبة في برنامجنا الأول، سنحتاج إلى تغييرات بسيطة لجعله يستغل مكتبة "أهلا بالعالم" كما هو موضح (تذكر: مشروعنا الأول في مجلد لوحده باسم sayhello):</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">package main

import "fmt"
import "github.com/01walid/sayhello"


func main() {
   fmt.Print(sayhello.SayHello())
}
</pre><p>قمنا فقط بجلب مكتبتنا الجديدة عبر كتابة:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint" style="line-height: 22.4px;">import "github.com/YOUR_USER/sayhello"</pre><p>ثم استعمالها عبر مناداة دالة <span style="font-family:courier new,courier,monospace;">SayHello</span> منها داخل <span style="font-family:courier new,courier,monospace;">fmt.Print</span> عوض كتابة "أهلا بالعالم" مباشرة:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint" style="line-height: 22.4px;">   fmt.Print(sayhello.SayHello())</pre><p>الآن شغّل البرنامج مجددا عبر كتابة <strong><span style="font-family:courier new,courier,monospace;">go run helloworld.go</span></strong>، هذا كل ما في الأمر!</p><p>تهانينا لك أول برنامج وأول مكتبة لك باستخدام لغة البرمجة Go!</p><h2 dir="rtl">إضافة (Bonus)</h2><p dir="rtl">في إضافة هذا الدرس، اخترت أن أشير إلى بعض إضافات محررات النصوص البرمجية الشهيرة، والتي من شأنها أن تسهل عليك البرمجة بـ Go بشكل معتبر.</p><p dir="rtl">ستجد <a rel="external nofollow" href="https://github.com/avelino/awesome-go#editor-plugins">من هنا قائمة بهذه الإضافات</a>، مثلا إن كنت من مستعملي SublimeText فقم بتنصيب إضافة <a rel="external nofollow" href="https://github.com/DisposaBoy/GoSublime">GoSublime</a> وإن كنت من مستعملي محرر Atom فقط بتنصيب<a rel="external nofollow" href="https://github.com/joefitzgerald/go-plus"> Go-plus</a>.</p><h2 dir="rtl">خاتمة</h2><p dir="rtl">تعرفنا في هذا الدرس على كيفية كتابة برنامج باستخدام لغة Go، ثم جعل البرنامج على شكل مكتبة عوض تركه في شكله التنفيذي.</p><p dir="rtl">من المهم جعل برامجك عبارة عن مجموعة مكتبات منفصلة حسب الغرض، عوض جعل كل شيء متداخل في حزمة واحد أو في برنامج تنفيذي. فكما رأينا إنشاء برنامج تنفيذي أسهل ما يكون، إذ يكفي كتابة ملف به <span style="font-family:courier new,courier,monospace;">package main</span> ثم <span style="font-family:courier new,courier,monospace;">func main </span>واستدعاء باقي الحزم<span style="font-family:courier new,courier,monospace;">،</span> بالتالي الأهم من ذلك هو التفكير التجريدي وفصل المهام عن بعضها في مكتبات وحزم حسب الغرض، كلٌ يقوم بمهمة/غرض ما، ويقوم به بشكل جيد ومُختبر (unit tests).</p><p dir="rtl">في درسنا هذا، كانت المكتبة منفصلة تماما عن البرنامج التنفيذي. مشاريعك القادمة ستكون على الأغلب مقسمة إلى حزم/مكتبات <strong>داخل مجلد المشروع نفسه</strong> وليس بالضرورة في مجلد/مشروع آخر، لكن المفهوم هو نفسه.</p><p dir="rtl">رأينا أيضا، أن التعليقات في Go وسيلة ممتازة لتوليد التوثيق بأدنى جهد، لذلك يجدر بك كمبرمج عدم إهمالها والاهتمام بها وبتفاصيلها.</p><p dir="rtl">كل هذا كان سهلا! لعلك كنت تسمع بهذه الأمور فتفزع (tests, docs, cover.. الخ) لكني قدمت هذه المفاهيم عمدا في الدروس الأولى لترى أن لا شيء يستحق الهروب منه. وأن البرامج ذات الجودة العالية مجرد اتباع لسلوكيات مهذبة وممارسات محبذة بخطوات ثابتة ينبغي أن تُعوّد نفسك عليها من الآن وتجعل منها أسلوب تطوير/برمجة.</p><p dir="rtl">في الدروس القادمة سنتطرق إلى أنواع المتغيرات، هيكلة البيانات، كيفية إنشاء متغير، الحلقات والجمل الشرطية.</p>
]]></description><guid isPermaLink="false">241</guid><pubDate>Fri, 22 Jan 2016 17:23:00 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645;&#x60C; &#x62A;&#x646;&#x635;&#x64A;&#x628; &#x648;&#x62A;&#x647;&#x64A;&#x626;&#x629; &#x628;&#x64A;&#x626;&#x629; &#x639;&#x645;&#x644; &#x644;&#x63A;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/golang-2.png.baea7f842809f956d266714f625c0d6c.png" /></p>

<p dir="rtl">بعد تعرُّفنا في الدرس السابق على <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/">لغة Go ونقاط اختلافها مع باقي لغات البرمجة</a>، سنحاول في هذا الدرس شرح كيفية تنصيبها، تهيئة وفهم بيئة العمل (Workspace) الخاصة بها. من المهم جدا فهم تقسيم المجلدات الذي تمليه عليك بيئة عمل Go، حيث سيمكّنك ذلك من ترتيب مشروعك بشكل أفضل، تسهيل مشاركته، وجعله قابلا للجلب والتضمين في مشاريع أخرى عبر أمر <span style="font-family:courier new,courier,monospace;">go get</span> الذي سنتعرّف عليه لاحقا.</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/golang-2.png.8365aaf4ce8f47a14e7b3853886e6f2f.png"><img data-fileid="10579" class="ipsImage ipsImage_thumbnailed" alt="golang-2.thumb.png.0e7373d317493e6e89b38" src="https://academy.hsoub.com/uploads/monthly_2015_12/golang-2.thumb.png.0e7373d317493e6e89b38f8b5d2b623c.png"></a></p><p dir="rtl">تملك Go نوعين من المُجمّعات (Compilers). وكتذكير سريع، وظيفة المُجمّع هي أخذ شيفرتك البرمجية في شكلها النصّي البحت، وتحويلها إلى برنامج تنفيذي (أو مكتبة). أحد مجمّعَيْ Go هو المجمع القياسي الذي يحمل اسم <span style="font-family:courier new,courier,monospace;">gc</span> اختصارًا لـ Go Compiler، والآخر مُجمّع يعتمد على مجمّع gcc وما يوفره كمنصة ودعم معماريات معالجات (CPU) أكثر ويحمل اسم <span style="font-family:courier new,courier,monospace;">gccgo</span>.</p><p dir="rtl">يجدر الإشارة إلى أن مجمع <span style="font-family:courier new,courier,monospace;">gccgo</span> متأخر نوعا ما في زرع كامل مواصفات النسخة الأحدث من Go، فعلى سبيل المثال، ولدى كتابة هذا الدرس، يوفر <span style="font-family:courier new,courier,monospace;">gccgo</span> نسخة 1.4.1 من Go في حين يوفر <span style="font-family:courier new,courier,monospace;">gc</span> دائما آخر نسخة (1.5.2) من اللغة.</p><p dir="rtl">ذكرت هذا من باب العلم بالشيء، وباختصار، إن لم يهمك دعم معماريات أكثر أو بعض تفاصيل منصة gcc فلن تحتاج إلى <span style="font-family:courier new,courier,monospace;">gccgo</span> وستكتفي بـ <span style="font-family:courier new,courier,monospace;">gc</span> القياسي وهو ما سنتبعه خلال هذه السلسلة.</p><h2 dir="rtl">تنصيب Go</h2><p dir="rtl">كما ذكرنا في الدرس السابق، فإن Go لغة متعددة المنصّات بامتياز، وهي جاهزة للتحميل والتنصيب على نظامك المفضل لكلا معماريتي <span style="font-family:courier new,courier,monospace;">32bit</span> و <span style="font-family:courier new,courier,monospace;">64bit</span>.</p><h3 dir="rtl"><span style="line-height: 14.9333px;">تنصيب Go </span>على Windows و Mac OS</h3><p dir="rtl">يكفي التوجه إلى موقع اللغة ثم <a rel="external nofollow" href="https://golang.org/dl/">تحميل النسخة الخاصة بنظامك</a>. عملية تنصيبها عادية وهي مشابهة لعملية تنصيب أي برنامج عادي آخر.</p><p dir="rtl"><span style="line-height: 22.4px;">بعد التنصيب، تأكد من أن العملية تمت بنجاح عبر كتابة </span><span style="line-height: 22.4px; font-family: 'courier new', courier, monospace;">go version</span><span style="line-height: 22.4px;"> أو فقط </span><span style="line-height: 22.4px; font-family: 'courier new', courier, monospace;">go</span><span style="line-height: 22.4px;"> في سطر الأوامر. إن كنت على Windows تأكد من غلق أي نافذة سطر أوامر مفتوحة مسبقا (إن وُجدت) ثم فتح نافذة جديدة.</span></p><h3 dir="rtl"><span style="line-height: 22.4px;">تنصيب Go على Linux</span></h3><p dir="rtl">أنصحك بالاطلاع على مدير حزم توزيعتك قبل تحميل وتنصيب Go من أي مكان آخر. فإن وجدت أن مدير حزم توزيعتك يوفر آخر نسخة من Go فسيكون الأمر أسهل بكثير، إن وجدت أن توزيعتك توفر نسخة أقدم من Go 1.5.1 فعليك تنصيب آخر نسخة منها إن كنت تريد متابعة هذه السلسلة.</p><p dir="rtl">إن كنت على Ubuntu والتوزيعات المبنية عليها، فأغلب الظن أن نسخة Go التي يوفرها مدير الحزم <span style="font-family:courier new,courier,monospace;">apt</span> قديمة، كون التوزيعة يتم تحديثها كل 6 أشهر أو عامين (في حال كانت LTS). لذلك أنصحك بالتنصيب من خلال إضافة مستودع etherneum.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install golang</pre><p dir="rtl">يُفترض بباقي التوزيعات أن تحتوي على آخر نسخة من Go، يكفي حينئذ التنصيب من مدير الحزم، مثلا على Arch Linux:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo pacman -S go</pre><p dir="rtl">بعد التنصيب، تأكد من أن عملية التنصيب تمت بنجاح عبر كتابة <span style="font-family:courier new,courier,monospace;">go version</span> أو فقط <span style="font-family:courier new,courier,monospace;">go</span> في سطر الأوامر. من المفروض تتلقى نتيجة مشابهة لهذه:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">go version go1.5.2 linux/amd64</pre><h2 dir="rtl">فهم بيئة العمل</h2><p dir="rtl">نقصد ببيئة العمل هنا أمران أساسيان:</p><ul dir="rtl"><li>مجلد على حاسوبك، تقوم بإنشائه في أي مكان تريد، سيكون مكانا لجميع مشاريع Go.</li><li>متغير بيئة (environment variable) يحمل اسم <strong><span style="font-family:courier new,courier,monospace;">GOPATH</span></strong> يشير إلى هذ المجلد.</li></ul><p>لنفرض أنك سمّيت مجلد العمل باسم <strong><span style="font-family:courier new,courier,monospace;">work</span></strong>، فإن هذا الأخير بدوره يجدر به أن يحوي ثلاث مجلدات فرعية أخرى:</p><ul><li><strong>مجلد فرعي باسم <span style="font-family:courier new,courier,monospace;">src</span></strong>، حيث ستضع فيه جميع الشيفرات البرمجية لكامل مشاريع Go خاصتك.</li><li><strong>مجلد فرعي باسم <span style="font-family:courier new,courier,monospace;">bin</span></strong>، حيث سيقوم مجمع <span style="font-family:courier new,courier,monospace;">gc</span> بنقل الملفات التنفيذية الناتجة عن شيفراتك البرمجية مباشرة إلى هذا المجلد.</li><li><strong>مجلد فرعي باسم <span style="font-family:courier new,courier,monospace;">pkg</span></strong>، مثل <span style="font-family:courier new,courier,monospace;">bin</span> لكن ليس للملفات التنفيذية، إن كتبت برنامجا عبارة عن مكتبة وليس برنامجا تنفيذيا في حد ذاته، أو جلبت مكتبة خارجية عبر أمر <span style="font-family:courier new,courier,monospace;">go get</span>، فسيتم تجميعها كمكتبة يتم وضعها في هذا المجلد حتى يسهل جلبها في باقي البرامج دون إعادة تجميعها في كل مرة (هذا يُسرّع من عملية تجميع برنامجك التنفيذي الذي يستخدم هذه المكتبات).</li></ul><p>باعتبار ما سبق، فإن بيئة Go ستكون مشابهة لهذا التقسيم الشجري:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">work      # مجلد العمل
├── bin   # مجلد الملفات التنفيذية الناتجة
├── pkg   # مجلد المكتبات البرمجية الناتجة
└── src   # مجلد شيفراتنا البرمجية
</pre><p><strong>هل هذا كل شيء؟ طبعا لا.</strong></p><p>بما أن Go لغة حديثة نسبيا، فإنها تفترض أنك ستستضيف شيفرتك البرمجية في مكان (مستودع) ما، وهذه عادة أي مبرمج محترف، خشية على الشيفرة البرمجية من الضياع أو من أجل مشاركتها مع أناس آخرين. طبعا مستودع شيفرتك البرمجية سيكون مُدارا بأحد <a rel="external nofollow" href="https://www.arabicgit.com/what-is-vcs/">أدوات إدارة النُسخ (VCS)</a> مثل <a rel="external nofollow" href="https://www.arabicgit.com/what-is-git/">Git</a> أو Mercurial مثلا. قد تكون الشيفرة على خادومك الخاص (Server)، أو على أحد خدمات استضافة المشاريع البرمجية مثل <a rel="external nofollow" href="https://github.com/">Github</a> و <a rel="external nofollow" href="https://bitbucket.org/">Bitbucket</a>.</p><p>بما أن Github أشهر المنصات لمشاركة الشيفرات البرمجية، فسأضرب به المثال.</p><p>تدفعك Go (أي أنه من المستحسن) إلى وضع شيفرتك البرمجية في مسار مشابه لمسار حسابك على github مثلا -وحتى أقرّب الصورة- لنفرض أن حسابك على github اسمه HsoubAcademy وبالتالي رابط حسابك هو:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">https://github.com/HsoubAcademy</pre><p>إذا أنشأت مشروعا بـ Go يحمل اسم example على سبيل المثال ثم رفعته على Github باستخدام حسابك <span style="line-height: 22.4px;">HsoubAcademy فسيكون رابط المشروع هو: </span></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">https://github.com/HsoubAcademy/example</pre><p>بالتالي فإن Go تدفعك ﻷن يكون مجلد المشروع على حاسوبك مشابها لهذا الرابط، أي تحت هذا المسار:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">work/src/github.com/HsoubAcademy/example</pre><p>حيث:</p><ul><li><span style="font-family:courier new,courier,monospace;">github.com</span> هو مجلد فرعي تحت مجلد <span style="font-family:courier new,courier,monospace;">src</span>.</li><li><span style="font-family:courier new,courier,monospace;">HsoubAcademy</span> هو مجلد فرعي تحت مجلد <span style="font-family:courier new,courier,monospace;">github.com</span> آنف الذكر، غيّره إلى حسابك على Github مثلا.</li><li><span style="font-family:courier new,courier,monospace;">example</span> هو مجلد فرعي يحوي ملفات مشروعك تحت مجلد <span style="line-height: 22.4px;"><span style="font-family:courier new,courier,monospace;">HsoubAcademy</span>.</span></li></ul><p><strong>ملاحظة</strong>: أسماء المجلدات حسّاسة لحالة الأحرف (case-sensitive) ماعدا على نظام Windows.</p><h3>لماذا ترتيب بيئة العمل بهذا الشكل؟</h3><p>ببساطة ﻷن التنظيم بهذا الشكل مفيد جدًا من ناحيتين: </p><p>1. بالإمكان جلب أي مكتبة خارجية بمجرد عمل <span style="font-family:courier new,courier,monospace;">import</span> لها من مسار مستودعها، مثلا: لنفرض أننا نريد استعمال مكتبة لنزع التشكيل عن النص العربي، سنستخدم <a rel="external nofollow" href="https://github.com/01walid/goarabic">مكتبة goarabic</a>، سيكفي لتضمينها في مشروعنا البرمجي كتابة الأمر:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">go get github.com/01walid/goarabic</pre><p>2. يقوم أمر <span style="font-family:courier new,courier,monospace;">go get</span> بوضع ناتج تجميع هذه المكتبة في مجلد <span style="font-family:courier new,courier,monospace;">pkg</span> بنفس مسار رابطها على github، أي سيضعها داخل مجلد فرعي باسم 01walid داخل مجلد github.com الذي هو بدوره عبارة عن مجلد فرعي داخل مجلد العمل، بالتالي يمكن تضمينها مباشرة في مشروعنا بهذا الشكل:  </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">import "github.com/01walid/goarabic" 
</pre><p>لاحظ أن مسار استيراد هذه المكتبة هو نفسه رابطها على github.</p><p>هذا يُسهّل من عملية مشاركة المكتبات البرمجية وإثراء مكتبات اللغة نفسها. من المهم جدا أن يتبع مشروعك نفس هذا المنهاج، خاصة إن كان عبارة عن مكتبة.</p><h2><span style="line-height: 22.4px;">تهيئة بيئة العمل</span></h2><p><strong>إن كنت على لينكس أو Mac OS</strong>، يمكنك مثلا إنشاء مجلد باسم <span style="font-family:courier new,courier,monospace;">work</span> داخل مجلد <span style="font-family:courier new,courier,monospace;">Home</span> خاصتك بكتابة أمر:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">mkdir $HOME/work</pre><p dir="rtl">ثم جعل هذا الأخير هو بيئة عمل Go عبر إنشاء متغير بيئة باسم GOPATH (حسّاس لحالة الأحرف) يُشير له:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">export GOPATH=$HOME/work</pre><p dir="rtl">طبعا لجعل هذا المتغير دائم حتى بعد إعادة التشغيل، سيكون عليك كتابته في <span style="font-family:courier new,courier,monospace;"><strong>bashrc.</strong></span> (في حال كنت تستعمل صدفة bash، أو ملف<strong><span style="font-family:courier new,courier,monospace;"> zshrc.</span></strong> إن كنت تستعمل صدفة zsh كمثال، وهي ملفات موجود داخل مجلد المنزل خاصتك <span style="font-family:courier new,courier,monospace;">HOME$</span>).</p><p dir="rtl"><strong>أما إن كنت على Windows</strong> فيكفي إضافة متغير باسم <span style="font-family:courier new,courier,monospace;">GOPATH</span> عبر التوجه إلى:</p><ul dir="rtl"><li>خصائص النظام (System -&gt; Advanced system settings)</li><li>ثم النقر على متغيرات البيئة (Environment Variables)</li><li>ثم إضافة المتغير من قسم System variables كما هو مبين أسفله.</li></ul><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/6ef223da-8a53-11e4-96bf-3cbbd9acf589.png.d18c6f39aecc426ff493d2a9e8d6e64c.png"><img data-fileid="10581" class="ipsImage ipsImage_thumbnailed" alt="6ef223da-8a53-11e4-96bf-3cbbd9acf589.thu" src="https://academy.hsoub.com/uploads/monthly_2015_12/6ef223da-8a53-11e4-96bf-3cbbd9acf589.thumb.png.a0a42bf1627627ff41391e09c5cd5bb9.png"></a></p><p dir="rtl">إذا كان مجلد عملك مثلا في Windows هو <strong><span style="font-family:courier new,courier,monospace;">C:\Projects\Go</span></strong> فسيكون عليك إضافته بهذا الشكل:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/feb28c94-8a53-11e4-9bf4-02728abe34e5.png.a6671b4386362e560ecd9d108f39d469.png"><img data-fileid="10580" class="ipsImage ipsImage_thumbnailed" alt="feb28c94-8a53-11e4-9bf4-02728abe34e5.thu" src="https://academy.hsoub.com/uploads/monthly_2015_12/feb28c94-8a53-11e4-9bf4-02728abe34e5.thumb.png.a3813eae2b6332417136aa69d9c74750.png"></a></p><p dir="rtl">يمكنك التحقق من أنه تم إضافة المتغير الجديد، عبر فتح نافذة سطر أوامر <strong>جديدة</strong>، وكتابة الأمر: <strong><span style="font-family:courier new,courier,monospace;">%echo %GOPATH</span></strong> كما هو موضح أسفله:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/39de5004-8a55-11e4-8140-ee39858cc1f4.png.8e4394fc4fe344ad3592476d8769b7d8.png"><img data-fileid="10582" class="ipsImage ipsImage_thumbnailed" alt="39de5004-8a55-11e4-8140-ee39858cc1f4.thu" src="https://academy.hsoub.com/uploads/monthly_2015_12/39de5004-8a55-11e4-8140-ee39858cc1f4.thumb.png.8b009847c2f0ea5cece90ad163ce9272.png"></a></p><p dir="rtl">إن تم إظهار المسار المُختار لمجلد عملك، فقد قمت أخيرًا بتنصيب Go وتهيئتها بنجاح.</p><h2 dir="rtl">إضافة (Bonus)</h2><p dir="rtl">ماذا لو أمكننا جعل البرامج التنفيذية التي نكتبها أو نجلبها عبر أمر <span style="font-family:courier new,courier,monospace;">go get</span> متوفرة مباشرة لدينا في نافذة سطر الأوامر دون التصفح إليها في كل مرة؟</p><p dir="rtl">مثلا لنقل أننا نريد الاستفادة من <a rel="external nofollow" href="https://github.com/HsoubAcademy/ha">أداة ha</a> المكتوبة بلغة Go، لتحويل ملفات Markdown إلى HTML جاهز للّصق على محرر آخر، نقوم بجلب الأداة:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">go get github.com/HsoubAcademy/ha</pre><p dir="rtl">بما أن أداة ha عبارة عن برنامج تنفيذي فإن أمر <span style="font-family:courier new,courier,monospace;">go get</span> سينقله مباشرة إلى مجلد <span style="font-family:courier new,courier,monospace;">bin</span> داخل بيئة العمل.</p><p dir="rtl">لكن لا نريد التنقل إلى مجلد <span style="font-family:courier new,courier,monospace;">bin</span> داخل مجلد العمل لاستعمالها، نريد فقط كتابة <span style="font-family:courier new,courier,monospace;">ha</span> في سطر الأوامر مباشرة للاستفادة من الأداة واستعمالها حتى وإن كنا في مجلد آحر.</p><p dir="rtl">بما أن Go تقوم بوضع ناتج الملفات التنفيذية في مجلد <span style="font-family:courier new,courier,monospace;">bin</span> تحت مجلد العمل، بالتالي، يكفي إضافة مسار مجلد <span style="font-family:courier new,courier,monospace;">bin</span> إلى مسارات متغير البيئة PATH ليكون كل شيء متوفر لديك! حتى برامجك التنفيذية التي تكتبها بنفسك.</p><p dir="rtl">بالنسبة لمستخدي Linux أو Mac OS فإن ذلك ممكن عبر إضافة مسار مجلد <span style="font-family:courier new,courier,monospace;">bin</span> داخل مجلد العمل إلى متغير البيئة PATH:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">export PATH=$PATH:$GOPATH/bin</pre><p dir="rtl">أما لمستخدمي Windows فعليهم إضافة مسار مجلد <span style="font-family:courier new,courier,monospace;">bin</span> داخل مجلد العمل إلى متغير البيئة PATH عبر التوجه إلى:</p><ul><li>خصائص النظام (System -&gt; Advanced system settings)</li><li>ثم النقر على متغيرات البيئة (Environment Variables)</li><li>البحث عن قيمة Path في قسم System variables ثم الضغط على edit وإضافة المسار إلى آخر السطة مسبوقا بفاصلة منقوطة (<span style="font-family:courier new,courier,monospace;"><strong>;</strong></span>) كما هو مبين أسفله.</li></ul><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/pathwin.png.16a83f87d6a7ae7dbcfa096e42fc5174.png"><img data-fileid="10602" class="ipsImage ipsImage_thumbnailed" alt="pathwin.thumb.png.edb3b10e12f3c63c958482" src="https://academy.hsoub.com/uploads/monthly_2015_12/pathwin.thumb.png.edb3b10e12f3c63c958482ef1d4e3417.png"></a></p><p dir="rtl">الآن ستجد أن كل ما هو موجود في مجلد <span style="font-family:courier new,courier,monospace;">bin</span> من برامج وأدوات متاح لك، من ذلك <a rel="external nofollow" href="https://github.com/HsoubAcademy/ha">أداة ha</a> التي أشرنا إليها سابقا (جرب فتح نافذة سطر أوامر جديدة وكتابة الأمر <span style="font-family:courier new,courier,monospace;">ha</span>).</p><p dir="rtl">بهذا نأتي إلى نهاية الدرس الثاني <a href="https://academy.hsoub.com/search/?tags=%D9%85%D8%AF%D8%AE%D9%84+%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">من هذه السلسلة</a>، سنشرع في الدرس القادم في كيفية بدء البرمجة بـ Go والاستفادة من بيئة العمل هذه.</p>
]]></description><guid isPermaLink="false">230</guid><pubDate>Thu, 31 Dec 2015 22:48:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x644;&#x63A;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; Go</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/golang-intro.png.56da8f18a0e2206099619d47eb484fab.png" /></p>

<p>لعلّك سمعت في السنوات القليلة الماضية عن لغة برمجة جديدة نشأت من داخل شركة Google تحمل اسم Go (أو Golang كمصطلح قابل للبحث على محركات البحث)، سنحاول من خلال هذه السلسلة التعرّف على هذه اللغة، مزاياها، عيوبها وما يجعلها مختلفة عن غيرها. سيكون الدرس الأول من <a href="https://academy.hsoub.com/search/?tags=%D9%85%D8%AF%D8%AE%D9%84+%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">هذه السلسلة</a> درسًا كلاميا فقط، يركز على نقاط اختلاف اللغة مع باقي اللغات، وهو موجه لمن له خلفية برمجية نوعا ما مع باقي اللغات، لكن ستكون باقي الدروس موجهة للمبتدئين.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/golang-intro.png.a2105315f4ca7d878b257ee03133cc90.png"><img data-fileid="10135" class="ipsImage ipsImage_thumbnailed" alt="golang-intro.thumb.png.2822a5bfd479f5edd" src="https://academy.hsoub.com/uploads/monthly_2015_12/golang-intro.thumb.png.2822a5bfd479f5edd46844d799fc160b.png"></a></p><p>كعادة كل عقد من الزمن، فإنه تظهر هناك أدوات وتقنيات جديدة تحاول الاستفادة من أخطاء أسلافها من الأدوات والتقنيات، هذا يشمل لغات البرمجة أيضا، لذلك دعك من قول "لماذا لغة برمجة جديدة؟" و "ما الحاجة للغة برمجة جديدة؟" أو "لماذا لا يتفقون على لغة برمجة واحدة؟"، فما لغة البرمجة إلا أداة تقضي بها مهامك، وكل منها يكون أصلح لنوع مهام ما. فاختر لكل مهمة أنسب أداة، ولا داعي لتقديس الأداة وإنشاء الحروب الكلامية -غير التقنية- حولها أو خلق هاجس وهمي يحول عن تعلمها. </p><p>أَحَسَّ فريقٌ من المبرمجين (العريقين) من داخل Google أنه حان الوقت لتحسين سير عملهم بلغة C و ++C، وأنهم يحتاجون إلى أداة جديدة تلغي عيوب هاتين الأخيرين وتحسن من إنتاجيتهم أكثر، وتكون ملائمة لنوعية احتياجات Google الحسابية. أسسوا لغة البرمجة Go داخل Google عام 2007. الفريق العريق المؤسس لهذه اللغة يشمل مؤسس نظام Unix نفسه <a rel="external nofollow" href="https://en.wikipedia.org/wiki/Ken_Thompson">Ken Thompson</a> (عَلَمٌ في عِلم الحاسوب، يُعرف اختصارًا بـ Ken) الذي عمل لدى Bell Labs، كذلك <a rel="external nofollow" href="https://en.wikipedia.org/wiki/Rob_Pike">Robert Pike</a> الذي كان أيضا من ضمن فريق Unix لدى Bell Labs وأحد مؤسسي ترميز UTF-8 وأخيرًا <a rel="external nofollow" href="https://en.wikipedia.org/wiki/Robert_Griesemer">Robert Griesemer</a> أحد العاملين على محرك جافاسكريب V8.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/Ken_n_dennis.jpg.b3cfe1006a35f4b3462680b0a7672c5e.jpg"><img data-fileid="10134" class="ipsImage ipsImage_thumbnailed" alt="Ken_n_dennis.thumb.jpg.21feeb72450095df8" src="https://academy.hsoub.com/uploads/monthly_2015_12/Ken_n_dennis.thumb.jpg.21feeb72450095df864db251fedb008d.jpg"></a></p><p style="text-align: center;"><span style="color:#A9A9A9;">Ken على يسار الصورة بجانب </span><a title="Dennis Ritchie" rel="external nofollow" href="https://en.wikipedia.org/wiki/Dennis_Ritchie"><span style="color:#A9A9A9;">Dennis Ritchie</span></a><span style="color:#A9A9A9;"> مؤسس لغة C</span></p><p>بمعرفة هذه النبذة التاريخية البسيطة عن Go، أحب أن أقتل فيك كل حماس مُفرط، فلا أحب منك أن تعشق لغة برمجة بسبب مؤسيسها، أو أنها خرجت من شركة تحبها، لذلك سأبدأ بسرد أشياء قد لا تحبها حول لغة البرمجة Go، حتى إذا قرأتها ولم تعجبك، فقد يجدر بك التوقف عن القراءة حينها. سأكون سعيدا شخصيا بمتابعة عدد قليل جدا من القراء لهذه السلسلة يدركون حقا ما يفعلون، عوض زخم يتحمس لكل جديد دون وعي وإلمام بالأمور.</p><h2>أشياء قد لن تحبها حول لغة البرمجة Go</h2><h3>1. ليست كائنية التوجه</h3><p>هذا إن كنت تظن أنها كذلك، فلا يوجد مفهوم الصنف (<span style="font-family:courier new,courier,monospace;">Class</span>) ولا الكائنات (<span style="font-family:courier new,courier,monospace;">Objects</span>) وبالتالي لا يوجد وراثة (inheritance). مع ذلك فإن Go <a rel="external nofollow" href="https://golang.org/doc/faq#Is_Go_an_object-oriented_language">تحمل بضعا من مزايا البرمجة الكائنية</a> كتوفيرها لـ Interface و دوال البنيات (Struct methods) وتركيب البنيات (Struct composition). </p><p><strong>لماذا</strong>؟ مؤسسي اللغة يرون أن اللغات كائنية التوجه تحمل العديد من العيوب والتعقيدات التي يمكن إلغاؤها بالتخلي عن بعض هذه المفاهيم كلية. حتى مبرمجي Java أنفسهم<a rel="external nofollow" href="http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance"> ينصحون بـ Composition</a> مثلا في كثير من الأحيان عوض inheritance، مؤسسي اللغة ممن يرون أن البرمجة كائنية التوجه <a rel="external nofollow" href="https://plus.google.com/+RobPikeTheHuman/posts/hoJdanihKwb">غالبا ما تكون فكرة سيئة -تقنيا-</a>.</p><h3>2. لا توجد معالجة للاستثناءات Exception Handling</h3><p>قد تكون هذه نتيجة طبيعية بسبب غياب مفهوم البرمجة الكائنية لدى Go، فمعالجة الأخطاء في Go تتم بطريقة واضحة وتقليدية نوعا ما، حيث أن الأخطاء تُرجع كقيم عادية من نوع <span style="font-family:courier new,courier,monospace;">error</span>. حيث <span style="font-family:courier new,courier,monospace;">error</span> هو نوع  بدائي في حد ذاته مثله مثل أي نوع أصلي آخر (<span style="font-family:courier new,courier,monospace;">int</span>, <span style="font-family:courier new,courier,monospace;">string</span> .. الخ). مع ذلك تسمح لك Go بقذف خطأ للحالات الاستثنائية عبر الكلمة المفتاحية panic (أشبه بـ <span style="font-family:courier new,courier,monospace;">raise</span>  أو <span style="font-family:courier new,courier,monospace;">throw</span> في باقي اللغات) وكذا التعافي من هذه الأخطاء عن طريق <span style="font-family:courier new,courier,monospace;">recover</span>.</p><h3>3. لا توجد معامِلات افتراضية أو اختيارية يمكن تمريرها للدوال (default/optional arguments)</h3><p>ربما قد اعتدت في لغات البرمجة الأخرى على القيام بشيء مثل:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint"> function listFolders(path, subfolders=false, recursive=false){ ... }</pre><p> لكن في Go لن يمكنك تمرير <span style="font-family:courier new,courier,monospace;">subfolder=false</span> ولا<span style="font-family:courier new,courier,monospace;"> recursive=false </span>كإمضاء للدالة <span style="font-family:courier new,courier,monospace;">listFolders</span> لأنها لن تقبل مثل هذه المعاملات الافتراضية/الاختيارية، وسينتج عن ذلك خطأ عند التجميع (compile error).</p><p><strong>لماذا</strong>؟ يرى مؤسسوا اللغة أن هذه السلوكيات تساهم في بناء واجهات برمجية (<span style="font-family:courier new,courier,monospace;"><abbr title="واجهة برمجية | Application Programming Interface">API</abbr></span>) غير ثابتة أو تساهم في جعل تصرفها غير مُتوقع. في مثالنا السابق مثلا، هم يفضلون كتابة الدالة من دون معاملات افتراضية، أي: </p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">func listFolders(path string, subfolders bool, recursive bool) { ... }</pre><p>يجبرك هذا على كتابة التصرف الذي تريده من الدالة بشكل صريح عوض ترك الواجهة البرمجية تملي عليك التصرف الافتراضي، هذا لتقليل الأخطاء البشرية. أيضا قد يدفعك هذا إلى كتابة ثلاث دوال، كل بتصرفها الخاص الواضح من اسمها، مثال: <span style="font-family:courier new,courier,monospace;">listFolders</span>, <span style="font-family:courier new,courier,monospace;">listFoldersRecursivly</span> و <span style="font-family:courier new,courier,monospace;">listFoldersWithFirstLevelSubFolders</span>.</p><h3>4. لا توجد ميزة إثقال الدوال (Method Overloading)</h3><p>لنفس الأسباب السابقة، فإنه لا يوجد Method overloading، أي لا يمكنك إعادة تعريف دالة تحمل نفس الاسم لكن بإمضاء مغاير. مثلا، إذا وُجدت دالة باسم:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">func listFolders(path string) { ... }</pre><p>فلا يمكنك إنشاء دالة أخرى بنفس الاسم لكن بإمضاء مغاير مثل:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">func listFolder(path string, level int) { ... }</pre><p>بل عليك تغيير اسمها إلى مثلا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">dunc listFolderToLevel(path string, level int) { ... }</pre><p><span style="line-height: 22.4px;">على الرغم من ذلك فهناك طريقة غير مباشرة لجعل دالة ما تقبل قيما اعتباطية عبر جعل الإمضاء من نوع <span style="font-family:courier new,courier,monospace;">{}interface</span> سنتطرق إليها في الدروس القادمة</span><span style="line-height: 22.4px;">.</span></p><h3>5. لا وجود للعموميات (generics)</h3><p>تمكّنك باقي اللغات من كتابة دوال أو أصناف عامة، حيث لا تصرّح عند كتابتها بنوع المعاملات التي تقبلها لكن تترك لها مهمة معرفة نوع المعاملات لاحقا عند استدعائها، لعل أقرب مثال هو ما توفره لغة Java مثلا في صنف <span style="font-family:courier new,courier,monospace;">&lt;List&lt;T</span> حيث <span style="font-family:courier new,courier,monospace;">T</span> يرمز إلى أي نوع يتم تحديده لاحقا، بالتالي يمكن إنشاء <span style="font-family:courier new,courier,monospace;">&lt;List&lt;String</span> أو <span style="font-family:courier new,courier,monospace;">&lt;List&lt;Integer</span> بكل سهولة مع الحفاظ على نفس الوظائف والعمليات التي يمكن إجراؤها على القائمة <span style="font-family:courier new,courier,monospace;">List</span> بشكل عام.</p><p>لا يوجد في Go مثل هذا، وعوضا عن ذلك فهناك <span style="font-family:courier new,courier,monospace;">{}interface</span> كنوع شامل يرضي جميع الأنواع، لكنه ليس كبديل تام لـ Generics.</p><p><strong>لماذا</strong>؟ سبب عدم توفر العموميات (Generics) في Go هو أن مؤسسيها لم يتبيّنوا بعد الطريقة الأنسب لهم لإضافة هذه الميزة إلى اللغة <a rel="external nofollow" href="https://golang.org/doc/faq#generics">دون زيادة حِمل أثناء وقت التشغيل</a> (run-time).</p><h3>6. Go لُغة مملة كما أنها ليست أفضل لغة برمجة!</h3><p>لشدة بساطة اللغة وعدم إتيانها بشيء جديد، فإن الكثيرين يعتبرها لغة مملة. فعدد الكلمات المفتاحية بها والأنواع الأصلية فيها ضئيل مقارنة بباقي اللغات، كما أنها تقلل كثيرا من وجود أكثر من طريقة للقيام بمهمة معينة.  حتى أنها لا تحتوي على حلقة <span style="font-family:courier new,courier,monospace;">while</span> وتقتصر فقط على حلقة <span style="font-family:courier new,courier,monospace;">for</span>، الكثيرون يعتبرون هذا من مزايا اللغة، لكني ذكرتها لك حتى لا تتوقع شيئا جديدا يصلح للتباهي.</p><p>أيضا لن تسمح لك اللغة بترك متغير دون استعمال أو استيراد شيء غير مستعمل (unused import/variable) ولن يقبل المُجمع (compiler) أبدا بذلك.</p><h3>7. لغة عنيدة</h3><p>مؤسسوا اللغة متشبثون برأيهم وقراراتهم في تصميم اللغة، فلا تتوقع تغيرات جوهرية قد تحدث على المدى القريب أو المتوسط في اللغة أو تغيرات في طريقة القيام بالأمور وسلوك المُجمّع (compiler). ولا داعي لفتح نقاشات فارغة حول تصميم اللغة وعيوبها إلا إذا كنت في نفس مستوى خبرتهم وحكمتهم.</p><p>هم نفسهم يصرحون بهذا، ويذكرون أن هناك خيارات ولغات برمجة أخرى إن لم تعجبك Go.</p><h3>8. لا يوجد إجماع على مدير حزم واحد</h3><p>تملك بايثون pip، وجافاسكريب تملك npm، وغيرهم من اللغات تملك مدير حزم (package manager) شهير أو متفق عليه، لا تخلو Go من مدير حزم، <a rel="external nofollow" href="https://github.com/avelino/awesome-go#package-management">فهي تملك الكثير من ذلك</a>، لكنها لم تتفق بعد على مدير حزم واحد ولا عن كيفية جلب وسرد الاعتماديات بطريقة قياسية، لكن حديثا يتم العمل على ذلك <a rel="external nofollow" href="https://github.com/golang/go/wiki/PackageManagementTools">عبر مفهوم Vendoring</a>.</p><p>هذه الأمور الثمانية، للذكر وليس للحصر من أشد الانتقادات التي توجّه إلى Go كلغة برمجة، فإن كنت توافقها فقد لا تناسبك اللغة، وإن كنت ترى أن من ورائها حكمة -مثلي- فأكمل قراءة المقال حول أمور قد تعجبك حول Go.</p><h2>أشياء قد تحبها حول لغة البرمجة Go</h2><h3>1. خيوط المعالجة المتوازية الخفيفة (goroutines)</h3><p>تسمح لك Go بعمل معالجة متوازية والاستفادة من كامل قوة المعالج (CPU) لديك بكل بساطة، حيث تملك ما يسمى بـ goroutine وهو خيط معالجة متوازي أخف من thread في باقي اللغات. يسمح لك هذا بإطلاق عشرات الآلاف من خيوط المعالجة المتوازية (عوض مثلا عشرات أو مئات threads فقط) دون عناء إنشائها وجعلها تتواصل فيما بينها أو تُكمّل بعضها البعض. يكفي مثلا لعمل دالة تعمل في خيط معالجة لوحدها بسبقها بالكلمة المفتاحية go، مثلا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">go func(){ // دالة نكرة تقوم بعمل أمور في خيط معالجة لوحدها
  ....
}</pre><p>هذا يسمح بكتابة تطبيقات عالية الأداء بشكل أسهل بكثير.</p><h3>2. لغة تجميعية سريعة (compiled)</h3><p>عكس Ruby, Python, Java و PHP فإن Go لغة تجميعية، حيث أن الناتج النهائي لبرنامجك سيكون عبارة عن ملف تنفيذي قائم بذاته يحوي جميع الاعتماديات اللازمة لتشغيله دون الحاجة لاعتماديات خارجية، هذا مفيد جدا في تطوير الويب مثلا للتخلص أو تقليص مشاكل الاعتمادية (<a rel="external nofollow" href="https://en.wikipedia.org/wiki/Dependency_hell">dependency hell</a>).</p><p>أيضا تساهم هذه الميزة في تسهيل عملية نشر التطبيق الخاص بك (deployment) حيث سيكون عليك فقط نقل الملف التنفيذي إلى الخادوم مثلا ثم تشغيله وكفى. لا حاجة لتنصيب أي شيء آخر لتشغيل برمجيتك، لا حاجة حتى لتنصيب Go على الخادوم نفسه.</p><p>قد يتبادر إلى الذهن أن عملية التجميع (compiling) قد تأخذ وقتا خاصة إذا كان حجم البرنامج كبيرا، لكن الحقيقة أن عملية تجميع Go سريعة جدا وفي كثير من الأحيان لن تلاحظها حتى.</p><h3>3. لغة إنتاجية</h3><p>بسبب أنها لغة مملة، فإنها تضيق عليك مجال المجادلة مع زميلك في العمل أو من يعمل معك على المشروع أو البحث عن أفضل طريقة -مذهلة- للقيام بشيء ما، فكل شيء واضح وبسيط.</p><h3>4. متعددة المنصات بامتياز</h3><p>نفس البرنامج يمكن إعادة تجميعه ليعمل على ويندوز، لينكس، Mac OSx أو حتى الهواتف الذكية ومعمارية ARM. حتى أنه بعد الإصدارة رقم 1.5 من Go يمكن إنشاء ملف تنفيذي لجميع المنصات من خلال المنصة التي أنت فيها، مثلا يمكن من خلال نظام لينكس إنشاء ملف تنفيذي لنظام ويندوز و Mac OS دون الحاجة ﻷن تكون على ذلك النظام.</p><h3>5. مكتبة قياسية قوية (Rich Standard Library)</h3><p>على الرغم من حداثة اللغة، فإن مكتبتها القياسية حققت تقدما في ظرف قياسي. وغالبا ما يُنصح بالاعتماد على المكتبة القياسية قدر الإمكان، حيث تحتوي على أمور كثيرة تحتاجها أغلب أنواع التطبيقات، حتى أنها تحتوي على محرك قوالب html، أدوات للتعامل مع ترميز json، تشفير كلمات المرور وغيرها من الأمور الصالحة للاستعمال في تطبيقات الويب على سبيل المثال.</p><h3>6. كل شيء Unicode افتراضا</h3><p>موضوع ترميز السلاسل النصية وكيفية التعامل مع الحرف رقميا كبير، لكن Go جعلت كل شيء unicode بشكل افتراضي إلا إذا تم تعيين غير ذلك صراحة. تملك Go نوع rune عوض نوع char في باقي اللغات، وهو ببساطة اختصار (alias) لنوع int32 فقط يشير إلى نقطة ترميز Unicode لذلك الحرف. بالتي فإن string في Go عبارة عن سلسلة rune وليس عن سلسلة char يشير إلى byte كما في C مثلا.</p><h3>7. أدوات مساعدة جيدة مضمنة </h3><p>يمكن توليد توثيق برمجيتك بمجرد كتابة أمر <span style="font-family:courier new,courier,monospace;">godoc</span> أو تحسين التنسيق بكتابة <span style="font-family:courier new,courier,monospace;">gofmt</span> أو بدء إجراءات فحص الشفرة البرمجية (Unit testing مثلا) عبر كتابة <span style="font-family:courier new,courier,monospace;">go test</span> وكلها أدوات تأتي مع تنصيب Go.</p><h3>8. لغة سهلة من حيث الكتابة والتنسيق (Syntax)</h3><p>تنسيق اللغة شبيه نوعا ما بلغة بايثون، حيث لا وجود للفاصلة المنقوطة بعد نهاية كل تعليمة (<strong><span style="font-family:courier new,courier,monospace;">;</span></strong>)، كما يمكن عمل متغير جديد دون تحديد نوعه، على الرغم من أن اللغة شديدة النوعية strongly styped إلا أنها توحي أنها سَلِسَة وديناميكية، مثلا يمكن كتابة <span style="font-family:courier new,courier,monospace;">age := 35</span> وسيتم اسناد نوع <span style="font-family:courier new,courier,monospace;">int</span> إلى المتغير <span style="font-family:courier new,courier,monospace;">age</span>. كما أنه يمكن للدوال إرجاع أكثر من قيمة كما في بايثون مثلا.</p><p>لعل أكثر شيء مغاير لباقي اللغات هو طريقة كتابة الدوال، حيث أن القيمة التي تُرجعها الدالة تُكتب على يمين الدالة (كما في Pascal) وليس على يسارها، مثلا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">func HelloHsoub() string {
   return "Hello Hsoub Academy!"
}</pre><p>لاحظ أنه تم كتابة <span style="font-family:courier new,courier,monospace;">string</span> على يمين الدالة وليس يسارها، أي أن هذه الدالة تُرجع قيمة من نوع string. يمكن للدوال إرجاع دوال أخرى أيضا كقيمة كما يمكن للمتغيرات أن تشير إلى دوال (كما في جافاسكريبت وبايثون...) مثلا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sayHi := HelloHsoub </pre><p> </p><p>حتى لا أنحاز، فهذه 8 أشياء قد تحبها سأتوقف عندها مقابل 8 قد لا تعجبك كنت قد ذكرتها.</p><p>بهذا نكون وصلنا إلى ختام الدرس الأول -الكلامي- من هذه السلسلة، والتي رأيت أن أبدأها هكذا عمدا ولو أن بعضا مما قيل في هذا الدرس قد لا يكون بالضرورة موجها للمبرمج المبتدئ، لكني سأحاول جعل <a href="https://academy.hsoub.com/search/?tags=%D9%85%D8%AF%D8%AE%D9%84+%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">الدروس القادمة</a> أبسط ما يكون وتُعنى بالمبتدئ أولا.</p>
]]></description><guid isPermaLink="false">222</guid><pubDate>Tue, 29 Dec 2015 08:43:00 +0000</pubDate></item></channel></rss>
