<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; Rust</title><link>https://academy.hsoub.com/programming/rust/page/3/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; Rust</description><language>ar</language><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x646;&#x648;&#x639; HashMap &#x644;&#x62A;&#x62E;&#x632;&#x64A;&#x646; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%86%D9%88%D8%B9-hashmap-%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1917/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_02/1630268450_--------hash-map--.png.78d29b5a7ed1db2e9b8c071a7c5841b4.png" /></p>
<p>
	نستعرض في هذا المقال آخر التجميعات الشائعة في <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> التي تحدثنا عنها سابقًا خلال رحلتنا في سلسلة <a href="https://academy.hsoub.com/tags/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%20%D8%A8%D9%84%D8%BA%D8%A9%20%D8%B1%D8%B3%D8%AA/" rel="">البرمجة بلغة رست</a> ألا وهي الخريطة المعمّاة hash map.
</p>

<h2>
	الخريطة المعماة HashMap
</h2>

<p>
	يخزّن النوع <code>HashMap&lt;K, V&gt;‎</code> ربطًا ما بين القيم من النوع <code>K</code> التي تمثل المفاتيح والقيم من النوع <code>V</code> التي تمثل القيم باستخدام دالة التعمية hashing function، التي تحدد أين يجب وضع هذه المفاتيح والقيم في الذاكرة. تدعم كثيرًا من <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> هذا النوع من هيكل البيانات إلا أنها غالبًا ما تستخدم اسمًا مختلفًا مثل النوع hash، أو خريطة map، أو كائن object، أو جدول hash، أو قاموس dictionary، أو مصفوفة مترابطة associative array والقائمة تطول.
</p>

<p>
	الخرائط المعمّاة مفيدة عندما تريد البحث عن بيانات دون استخدام دليل لها كما هو الحال في الأشعة vectors وإنما باستخدام مفتاح key قد يكون من أي <a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">نوع بيانات</a>. على سبيل المثال، يمكنك تتبع نتيجة كل فريق في لعبة ما باستخدام الخريطة المعمّاة باستخدام اسم الفريق مفتاحًا للقيمة ونتيجة كل فريق مثل قيم، ويمكنك بالتالي الحصول على نتيجة الفريق باستخدام اسمه.
</p>

<p>
	سنستعرض <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">مبادئ الواجهة البرمجية</a> الخاصة بالخرائط المعمّاة في هذا المقال، إلا أن هناك المزيد من الأشياء المثيرة للاهتمام الموجودة ضمن <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">الدوال</a> المُعرّفة في <code>HashMap&lt;K, V&gt;‎</code> ضمن المكتبة القياسية، ولكن عليك التحقق من توثيق المكتبة القياسية إذا أردت المزيد من التفاصيل.
</p>

<h2>
	إنشاء خريطة معماة HashMap جديدة
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_10" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let mut scores </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Yellow"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	[الشيفرة 20: إنشاء خريطة معماة جديدة وإضافة بعض المفاتيح والقيم إليها]
</p>

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

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

<h2>
	الوصول إلى القيم في الخريطة المعماة
</h2>

<p>
	يمكننا الحصول على قيمة في الخريطة المعماة باستخدام مفتاحها وتابع <code>get</code> كما هو موضح في الشيفرة 21.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_12" style=""><span class="pln">   fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let mut scores </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Yellow"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln">

    let team_name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">);</span><span class="pln">
    let score </span><span class="pun">=</span><span class="pln"> scores</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(&amp;</span><span class="pln">team_name</span><span class="pun">).</span><span class="pln">copied</span><span class="pun">().</span><span class="pln">unwrap_or</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 21: الوصول إلى نتيجة الفريق الأزرق المخزنة في الخريطة المعمّاة]
</p>

<p>
	سيأخذ <code>score</code> القيمة المرتبطة مع الفريق الأزرق وستكون النتيجة 10. يُعيد التابع <code>get</code> قيمةً من النوع <code>Option&lt;&amp;V&gt;‎</code> وبالتالي إذا لم يكن هناك أي قيمة للمفتاح المحدد في الخريطة المعمّاة، فسيعيد التابع <code>get</code> القيمة <code>None</code>. يتعامل هذا البرنامج مع <code>Option</code> باستدعاء <code>unwrap_or</code> لضبط <code>score</code> إلى صفر إذا كان <code>score</code> لا يحتوي على قيمة للمفتاح المحدّد.
</p>

<p>
	يمكننا المرور على كل زوج مفتاح/قيمة في الخريطة المعمّاة بطريقة مشابهة لما نفعل في الأشعة عن طريق حلقة <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_14" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let mut scores </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Yellow"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">50</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">key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> in </span><span class="pun">&amp;</span><span class="pln">scores </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"{}: {}"</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	ستطبع الشيفرة البرمجية السابقة كل زوج بترتيب عشوائي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_16" style=""><span class="typ">Yellow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pln">
</span><span class="typ">Blue</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span></pre>

<h2>
	الخرائط المعماة والملكية
</h2>

<p>
	تُنسخ القيم التي تطبّق السمة <code>Copy</code>، مثل <code>i32</code> إلى الخريطة المعماة؛ بينما تُنقل القيم للأنواع المملوكة، مثل <code>String</code> وتصبح الخريطة المعماة مالكةً لهذه القيم كما هو موضح في الشيفرة 22.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9826_8" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let field_name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Favorite color"</span><span class="pun">);</span><span class="pln">
    let field_value </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">);</span><span class="pln">

    let mut </span><span class="typ">map</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">map</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">field_name</span><span class="pun">,</span><span class="pln"> field_value</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// ‫يصبح كل من field_name و field_value غير صالح بحلول هذه النقطة</span><span class="pln">
    </span><span class="com">// حاول استخدامهما وانظر إلى خطأ المصرف الذي ستحصل عليه</span></pre>

<p style="text-align: center;">
	[الشيفرة 22: توضيح أن المفاتيح والقيم تصبح مملوكة من قبل الخريطة المعماة فور إدخالها إليها]
</p>

<p>
	لا يمكننا استخدام القيمتين <code>field_name</code> و <code>field_value</code> بعد نقلهما إلى الخريطة المعماة باستدعاء التابع <code>insert</code>.
</p>

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

<h2>
	تحديث قيم خريطة معماة
</h2>

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

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

<h3>
	الكتابة على القيمة
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_20" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let mut scores </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"{:?}"</span><span class="pun">,</span><span class="pln"> scores</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	[الشيفرة 23: استبدال قيمة مخزّنة في خريطة معمّاة باستخدام مفتاحها]
</p>

<p>
	ستطبع الشيفرة البرمجية السابقة ‎<code>{"Blue": 25}</code>، إذ كُتِبَ على القيمة 10 السابقة القيمة 25.
</p>

<h3>
	إضافة مفتاح وقيمة فقط في حال عدم وجود المفتاح
</h3>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_22" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let mut scores </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">

    scores</span><span class="pun">.</span><span class="pln">entry</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Yellow"</span><span class="pun">)).</span><span class="pln">or_insert</span><span class="pun">(</span><span class="lit">50</span><span class="pun">);</span><span class="pln">
    scores</span><span class="pun">.</span><span class="pln">entry</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Blue"</span><span class="pun">)).</span><span class="pln">or_insert</span><span class="pun">(</span><span class="lit">50</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"{:?}"</span><span class="pun">,</span><span class="pln"> scores</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	[الشيفرة 24: استخدام التابع entry لإدخال قيمة فقط في حال لا يحتوي المفتاح على قيمة مرتبطة به]
</p>

<p>
	التابع <code>or_insert</code> في <code>Entry</code> معرّف ليُعيد <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">مرجعًا</a> قابلًا للتعديل يشير إلى قيمة المفتاح <code>Entry</code> إذا كان المفتاح المحدد موجودًا، وإلا سيدخل قيمة المعامل على أنها قيمة جديدة للمفتاح وسيُعيد مرجعًا قابلًا للتعديل إلى القيمة الجديدة، وهذه الطريقة أفضل من كتابة المنطق ذلك بأنفسنا، كم أنها تعمل بصورةٍ أفضل مع مدقق الاستعارة borrow checker.
</p>

<p>
	بتشغيل الشيفرة 24، نحصل على الخرج <code>{Yellow": 50, "Blue": 10"}</code>، إذ سيتسبب الاستدعاء الأول للتابع <code>entry</code> بإضافة مفتاح الفريق الأصفر بالقيمة 50 لأن الفريق الأصفر لا يحتوي على أي قيمة بعد، بينما لن يُغيّر الاستدعاء الثاني للتابع <code>entry</code> الخريطة المعمّاة لأن مفتاح الفريق الأزرق موجود مسبقًا بقيمة 10.
</p>

<h3>
	تحديث قيمة بحسب قيمتها السابقة
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5403_24" style=""><span class="pln">    use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

    let text </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hello world wonderful world"</span><span class="pun">;</span><span class="pln">

    let mut </span><span class="typ">map</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> word in text</span><span class="pun">.</span><span class="pln">split_whitespace</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        let count </span><span class="pun">=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">.</span><span class="pln">entry</span><span class="pun">(</span><span class="pln">word</span><span class="pun">).</span><span class="pln">or_insert</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">count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"{:?}"</span><span class="pun">,</span><span class="pln"> </span><span class="typ">map</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	[الشيفرة 25: عدّ عدد مرات ظهور الكلمات باستخدام خريطة معماة تخزّن الكلمة وعدد مرات ظهورها]
</p>

<p>
	ستطبع الشيفرة البرمجية <code>{world": 2, "hello": 1, "wonderful": 1"}</code>.
</p>

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

<p>
	يُعيد التابع <code>split_whitespace</code> مؤشرًا يشير إلى الشرائح الجزئية ضمن <code>text</code> والمفصول ما بينها بالمسافة، بينما يعيد التابع <code>or_insert</code> مرجعًا قابلًا للتعديل (<code>‎&amp;mut V</code>) إلى قيمة المفتاح المُحدّد، ونخزّن هنا المرجع القابل للتعديل في المتغير <code>count</code>، لذا ومن أجل الإسناد إلى تلك القيمة علينا أولًا أن نُحصّل المتغير <code>count</code> باستخدام رمز النجمة <code>*</code>. تخرج المراجع القابلة للتعديل من النطاق في نهاية الحلقة <code>for</code>، لذا جميع هذه التغييرات آمنة ومسموحة استنادًا لقوانين الاستعارة.
</p>

<h2>
	دوال التعمية hashing function
</h2>

<p>
	تستخدم الخريطة المعماة <code>HashMap</code> افتراضيًا دالة تعمية hashing function تدعى <a href="https://en.wikipedia.org/wiki/SipHash" rel="external nofollow">SipHash</a>، وهي دالة توفر حمايةً لخرائط التعمية ضد هجمات الحرمان من الخدمة Denial of Service -أو اختصارًا DoS- إلا أنها ليست أسرع <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">خوارزميات</a> التعمية المتاحة ولكنها تقدم حمايةً أفضل، والتراجع في السرعة مقابل ذلك يستحقّ المساومة.
</p>

<p>
	إذا راجعت شيفرتك البرمجية ورأيت أن دالة التعمية الاعتيادية بطيئة جدًا مقارنةً بحاجتك، فيمكنك استبدالها بدالة أخرى بتحديد مُعَمّي hasher؛ والمعمّي هو النوع الذي يطبّق السمة <code>BuildHasher</code> وسنناقش السمات بالتفصيل لاحقًا. ليس من الضروري كتابة المعمّي الخاص بك بنفسك، إذ يحتوي <a href="https://crates.io/" rel="external nofollow">crates.io</a> على مكتبات شاركها مستخدمو رست آخرون لتقديم تطبيق معمّي معيّن باستخدام خوارزميات التعمية الشهيرة.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html" rel="external nofollow">Common Collections</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1920/" rel="">الأخطاء والتعامل معها في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A8%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-utf-8-%D8%AF%D8%A7%D8%AE%D9%84-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1876/" rel="">تخزين النصوص بترميز UTF-8 داخل السلاسل النصية في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D9%84%D8%A7%D8%A6%D8%AD%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D9%82%D9%8A%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D8%B9%D8%A9-vectors-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1875/" rel="">تخزين لائحة من القيم باستخدام الأشعة Vectors في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%B4%D8%AC%D8%B1%D8%A9-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A9-module-tree-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1873/" rel="">المسارات paths وشجرة الوحدة module tree في رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1917</guid><pubDate>Fri, 03 Mar 2023 16:02:00 +0000</pubDate></item><item><title>&#x62A;&#x62E;&#x632;&#x64A;&#x646; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x628;&#x62A;&#x631;&#x645;&#x64A;&#x632; UTF-8 &#x62F;&#x627;&#x62E;&#x644; &#x627;&#x644;&#x633;&#x644;&#x627;&#x633;&#x644; &#x627;&#x644;&#x646;&#x635;&#x64A;&#x629; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A8%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-utf-8-%D8%AF%D8%A7%D8%AE%D9%84-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1876/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1033733167_---UTF-8----strings----Rust.png.cc315ff688b24ace2e2f7d4fe0510125.png" /></p>
<p>
	أتينا على ذكر السلاسل النصية سابقًا إلا أننا لم ننظر إليها بالتفصيل بعد، إذ يجد متعلمو لغة رست فهم السلاسل النصية صعبًا لثلاثة أسباب رئيسية: ميل رست لاستباق الخطأ قبل حدوثه وعرض رسالة خطأ تدلّ عليه، كما يبدو هيكل بيانات السلاسل النصية أكثر صعوبةً وتعقيدًا مما تبدو عليه، وأخيرًا ترميز UTF-8. قد تجتمع جميع الأسباب الثلاث السابقة وتجعل من الصعب عليك فهم السلاسل النصية إن قدمت من لغات برمجة مختلفة.
</p>

<p>
	نناقش السلاسل النصية هنا في سياق التجميعات collections، وذلك لأن السلاسل النصية هي تطبيق لتجميعة من البايتات إضافةً إلى بعض <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">التوابع</a> المفيدة الأخرى، والتي تبرز أهميتها عندما تمثّل هذه البايتات نصًا ما. سنتحدث في هذا المقال عن العمليات على السلاسل النصية <code>String</code> الموجودة في كل نوع تجميعة، مثل إنشاء سلسلة نصية والتعديل عليها وقراءة محتوياتها، كما سنناقش أيضًا الطرق التي تختلف فيها السلاسل النصية عن التجميعات الأخرى وبالأخص استخدام دليل السلسلة النصية للوصول إلى محتوياتها، فهو معقد نظرًا لاختلافه مع ما يفسّره البشر لبيانات سلسلة نصية وما تفسره الحواسيب.
</p>

<h2>
	ما هي السلسلة النصية؟
</h2>

<p>
	دعنا نبدأ أولًا بتعريف ما الذي نقصده عندما نقول سلسلة نصية؛ إذ تمتلك رست نوع سلسلة نصية واحد في أساس اللغة وهو شريحة السلسلة النصية string slice‏ <code>str</code>، الذي نراه عادةً بشكله المختصر <code>‎&amp;str</code>. تحدثنا <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">سابقًا</a> عن شرائح السلاسل النصية؛ وهي مراجع إلى بعض بيانات السلاسل النصية المرمزة بترميز UTF-8 والمخزنة في مكان آخر. على سبيل المثال، تُخزَّن السلاسل النصية المجرّدة string literals في ملف البرنامج الثنائي وبالتالي فهي شرائح سلسلة نصية.
</p>

<p>
	النوع <code>String</code> الموجود في مكتبة رست القياسية بدلًا من وجوده في أساس اللغة، هو نوع سلسلة نصية قابل للتعديل mutable وللنمو growable والامتلاك owned ومُرمَّز بترميز UTF-8. عندما يقول مبرمجو <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">لغة رست</a> "سلسلة نصية" في رست فهم يقصدون إما النوع <code>String</code> أو أنواع شريحة السلسلة النصية <code>‎&amp;str</code> ولا يقتصر الأمر على واحد من النوعَين. على الرغم من أن هذا المقال يتكلم خاصةً على النوع <code>String</code> إلا أن كلا النوعين مُستخدمان جدًا في مكتبة رست القياسية، وكلٌ من النوع <code>String</code> وشريحة السلسلة النصية مُرمّزَان بترميز UTF-8.
</p>

<h2>
	إنشاء سلسلة نصية جديدة
</h2>

<p>
	الكثير من العمليات المتاحة في النوع <code>Vec&lt;T&gt;‎</code> هي عمليات متاحة في النوع <code>String</code> أيضًا، وذلك لأن النوع <code>String</code> هو تطبيق لمُغلَّف wrapper حول شعاع من البايتات، إضافةً إلى بعض الضمانات والقيود والإمكانات الأخرى. الدالة <code>new</code> هي مثال على دالة تعمل بنفس الطريقة على <code>Vec&lt;T&gt;‎</code> وعلى <code>String</code> سويًا لإنشاء نسخة instance كما هو موضح في الشيفرة 11.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_7" style=""><span class="pln">let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span></pre>

<p style="text-align: center;">
	الشيفرة 11: إنشاء نسخة جديدة وفارغة من النوع String
</p>

<p>
	يُنشئ السطر السابق سلسلةً نصيةً جديدةً وفارغة بالاسم <code>s</code>، وبالتالي يمكننا الآن إضافة <a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">البيانات</a> إليها، وسنحتاج غالبًا في البداية إلى بيانات تهيئة لتخزينها في السلسلة النصية، ونستخدم لهذا الغرض التابع <code>to_string</code>؛ وهو تابع متاح في أي نوع يطبّق السمة‏ <code>Display</code> وهو ما تفعله السلسلة النصية المجردة، توضح الشيفرة 12 مثالين على ذلك.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_9" style=""><span class="pln">    let data </span><span class="pun">=</span><span class="pln"> </span><span class="str">"initial contents"</span><span class="pun">;</span><span class="pln">

    let s </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">to_string</span><span class="pun">();</span><span class="pln">

    </span><span class="com">//تعمل هذه الدالة على السلاسل النصية المجردة مباشرةً</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"initial contents"</span><span class="pun">.</span><span class="pln">to_string</span><span class="pun">();</span></pre>

<p style="text-align: center;">
	الشيفرة 12: استخدام التابع to_string لإنشاء النوع String من سلسلة نصية مجردة
</p>

<p>
	تُنشئ الشيفرة البرمجية السابقة سلسلة نصية تحتوي على بيانات تهيئة <code>initial contents</code>.
</p>

<p>
	يمكننا أيضًا استخدام الدالة <code>String::from</code> لإنشاء النوع <code>String</code> من سلسلة نصية مجردة، والشيفرة 13 مكافئة للشيفرة 12 التي تستخدم التابع <code>to_string</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_11" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"initial contents"</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 13: استخدام الدالة String::from لإنشاء النوع String من سلسلة نصية مجردة
</p>

<p>
	بما أن السلاسل النصية تُستخدم للعديد من الأشياء، يمكننا استخدام عدة واجهات برمجية عامة لها، إذ تزودنا هذه الواجهات بكثيرٍ من الخيارات، وقد يبدو بعضها مكرّرًا إلا أن جميعها تؤدي غرضًا ما. في هذه الحالة، يؤدي كلًا من <code>String::from</code> و <code>to_string</code> الغرض ذاته، واستخدام أي منهما يعود إلى أسلوبك في كتابة الشيفرات البرمجية.
</p>

<p>
	تذكر أن السلاسل النصية تستخدم ترميز UTF-8 وهذا يعني أنه يمكننا تضمين أي بيانات بهذا الترميز، ألقِ نظؤةً على الشيفرة 14.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_13" style=""><span class="pln">    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"السلام عليكم"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Dobrý den"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"שָׁלוֹם"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"नमस्ते"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"こんにちは"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"안녕하세요"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"你好"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Olá"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Здравствуйте"</span><span class="pun">);</span><span class="pln">
    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Hola"</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 14: تخزين رسالة تحية بلغات مختلفة في سلاسل نصية
</p>

<p>
	تحتوي جميع السلاسل النصية السابقة قيمًا صالحة من النوع <code>String</code>.
</p>

<h2>
	تحديث سلسلة نصية
</h2>

<p>
	يمكن أن يكبر حجم النوع <code>String</code> وأن تتغير محتوياته بصورةٍ مشابهة للنوع <code>Vec&lt;T&gt;‎</code> عند إضافة مزيدٍ من البيانات إليه، ويمكنك إضافةً إلى ذلك استخدام العامل <code>+</code> أو الماكرو <code>format!‎</code> لضمّ concatenate عدّة قيم من النوع <code>String</code>.
</p>

<h3>
	إضافة قيم إلى السلسلة النصية باستخدام push_str و push
</h3>

<p>
	يمكننا توسعة حجم النوع <code>String</code> باستخدام التابع <code>push_str</code> لإضافة شريحة سلسلة نصية كما هو موضح في الشيفرة 15.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_15" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"foo"</span><span class="pun">);</span><span class="pln">
    s</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="str">"bar"</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 15: إضافة شريحة سلسلة نصية إلى النوع String باستخدام التابع push_str
</p>

<p>
	ستحتوي السلسلة النصية <code>s</code> -بعد السطرين البرمجيين السابقين- على <code>foobar</code>، إذ يأخذ التابع <code>push_str</code> شريحة سلسلة نصية لأننا لسنا بحاجة لأخذ ملكية المعامل، على سبيل المثال نريد في الشيفرة 16 أن نكون قادرين على استخدام <code>s2</code> بعد إضافة محتوياته إلى <code>s1</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_17" style=""><span class="pln">    let mut s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"foo"</span><span class="pun">);</span><span class="pln">
    let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"bar"</span><span class="pun">;</span><span class="pln">
    s1</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="pln">s2</span><span class="pun">);</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"s2 is {}"</span><span class="pun">,</span><span class="pln"> s2</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 16: استخدام شريحة سلسلة نصية بعد إضافة محتوياتها إلى النوع String
</p>

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

<p>
	يأخذ التابع <code>push</code> محرفًا وحيدًا مثل معامل ويُضيفه إلى النوع <code>String</code>، ونُضيف في الشيفرة 17 الحرف "I" إلى النوع <code>String</code> باستخدام التابع <code>push</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_19" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"lo"</span><span class="pun">);</span><span class="pln">
    s</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'l'</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 17: إضافة محرف واحد إلى قيمة من النوع String باستخدام push
</p>

<p>
	ستحتوي السلسلة النصية <code>s</code> نتيجةً لما سبق على <code>lol</code>.
</p>

<h3>
	ضم السلاسل النصية باستخدام العامل + أو الماكرو format!‎
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_21" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Hello, "</span><span class="pun">);</span><span class="pln">
    let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"world!"</span><span class="pun">);</span><span class="pln">
    let s3 </span><span class="pun">=</span><span class="pln"> s1 </span><span class="pun">+</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s2</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ‎‫لاحظ أن s1 نُقلَت إلى هنا ولا يمكن استخدامها بعد الآن</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 18: استخدام العامل + لضم قيمتين من النوع String إلى قيمة أخرى جديدة من النوع String
</p>

<p>
	ستحتوي السلسلة النصية <code>s3</code> بعد تنفيذ الشيفرة السابقة على "Hello, world!‎"، والسبب في عدم كون <code>s1</code> صالحة بعد عملية الجمع إلى استخدامنا مرجع إلى <code>s2</code> يعود إلى بصمة التابع method signature الذي استدعيناه عندما استخدمنا العامل <code>+</code>، إذ يستخدم هذا العامل التابع <code>add</code> وتبدو بصمته كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_23" style=""><span class="pln">fn add</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	ستجد التابع <code>add</code> معرفًا في المكتبة القياسية باستخدام الأنواع المعمّاة generics والأنواع المترابطة associated types، إلا أننا استبدلنا هذه الأنواع بأنواع فعلية وهو ما يحدث عند استدعاء هذا التابع بقيمٍ من النوع <code>String</code> (سنناقش الأنواع المعمّاة لاحقًا)، تعطينا بصمة التابع أدلة يجب علينا فهمها لفهم العامل <code>+</code>.
</p>

<p>
	أولًا، لدى <code>s2</code> الرمز <code>&amp;</code> أي أننا نُضيف مرجعًا للسلسلة النصية الثانية إلى السلسلة النصية الأولى، وهذا بسبب المعامل <code>s</code> في الدالة، إذ يمكننا جمع <code>‎&amp;str</code> إلى النوع <code>String</code> فقط وليس بإمكاننا إضافة قيمتين من النوع <code>String</code> سويًا، ولكن تمهّل، نوع <code>‎&amp;s2</code> هو <code>‎&amp;String</code> وليس <code>‎&amp;str</code> كما هو موضح في المعامل الثاني للتابع <code>add</code>. إذًا، لمَ تُصرَّف الشيفرة 18 بنجاح؟
</p>

<p>
	السبب في كوننا قادرين على استخدام <code>‎&amp;s2</code> في استدعاء <code>add</code> هو أن المصرف هنا قادرٌ على تحويل الوسيط <code>‎&amp;String</code> قسريًا إلى <code>‎&amp;str</code>، وعند استدعاء للتابع <code>add</code>، تستخدم رست <strong>التحصيل القسري deref corecion</strong> الذي يحوّل <code>‎&amp;s2</code> إلى <code>‎&amp;s2[..]‎</code> (سنناقش التحصيل القسري بمزيدٍ من التفاصيل لاحقًا)، ولأن <code>add</code> لا يأخذ ملكية المعامل <code>s</code> السلسلة <code>s2</code>، ستظل قيمةً صالحةً من النوع <code>String</code> بعد هذه العملية.
</p>

<p>
	ثانيًا، يمكننا في بصمة التابع رؤية أن <code>add</code> يأخذ ملكية <code>self</code>، لأن <code>self</code> لا تحتوي على الرمز <code>&amp;</code>، وهذا يعني أن السلسلة <code>s1</code> في الشيفرة 18 ستُنقل إلى استدعاء <code>add</code> ولن تصبح قيمةً صالحةً بعد ذلك، لذلك يبدو السطر البرمجي <code>let s3 = s1 + &amp;s2;‎</code> بأنه ينسخ كلا السلسلتين النصيتين ويُنشئ سلسلةً جديدةً، إلا أنه في الحقيقة يأخذ ملكية <code>s1</code> ويُسند نسخةً من محتويات <code>s2</code> إلى نهايتها ومن ثم يُعيد ملكية النتيجة؛ أي بكلمات أخرى يبدو أن السطر البرمجي يُنشئ كثيرًا من النُسخ إلا أنه في حقيقة الأمر لا يفعل ذلك، وهذا التطبيق فعال أكثر من النسخ.
</p>

<p>
	يصبح سلوك العامل <code>+</code> غير عملي في حال أردنا ضمّ عدة سلاسل نصية في نفس الوقت:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_25" style=""><span class="pln">    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"tic"</span><span class="pun">);</span><span class="pln">
    let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"tac"</span><span class="pun">);</span><span class="pln">
    let s3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"toe"</span><span class="pun">);</span><span class="pln">

    let s </span><span class="pun">=</span><span class="pln"> s1 </span><span class="pun">+</span><span class="pln"> </span><span class="str">"-"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s2 </span><span class="pun">+</span><span class="pln"> </span><span class="str">"-"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s3</span><span class="pun">;</span></pre>

<p>
	بحلول هذه النقطة، ستكون قيمة السلسلة <code>s</code> هي "tic-tac-toe"، إلا أن الأمر صعب المعرفة فورًا باستخدام محارف <code>+</code> و <code>"</code>. يمكننا استخدام الماكرو <code>format!‎</code> لعمليات ضم السلاسل النصية الأكثر تعقيدًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_27" style=""><span class="pln">    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"tic"</span><span class="pun">);</span><span class="pln">
    let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"tac"</span><span class="pun">);</span><span class="pln">
    let s3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"toe"</span><span class="pun">);</span><span class="pln">

    let s </span><span class="pun">=</span><span class="pln"> format</span><span class="pun">!(</span><span class="str">"{}-{}-{}"</span><span class="pun">,</span><span class="pln"> s1</span><span class="pun">,</span><span class="pln"> s2</span><span class="pun">,</span><span class="pln"> s3</span><span class="pun">);</span></pre>

<p>
	نحصل على القيمة "tic-tac-toe" في السلسلة <code>s</code> أيضًا بتنفيذ الشيفرة السابقة، إذ يعمل الماكرو <code>format!‎</code> على نحوٍ مماثل لعمل الماكرو <code>println!‎</code> إلا أنه يُعيد قيمةً من النوع <code>String</code> بدلاً من طباعة الخرج على الشاشة. نلاحظ أن الشيفرة البرمجية التي تستخدم الماكرو <code>format!‎</code> أسهل قراءةً من سابقتها. تستخدم الشيفرة المولّدة عن طريق استخدام الماكرو <code>format!‎</code> المراجع، لذلك لن يتسبب استدعائها بأخذ ملكية أي من معاملاتها.
</p>

<h2>
	الحصول على محتويات السلسلة النصية باستخدام الدليل
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_29" style=""><span class="pln">    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">
    let h </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span></pre>

<p style="text-align: center;">
	الشيفرة 19: محاولة الوصول إلى أجزاء من السلسلة النصية باستخدام دليلها
</p>

<p>
	ستتسبب الشيفرة البرمجية السابقة بظهور الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_31" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> collections v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/collections)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0277</span><span class="pun">]:</span><span class="pln"> the type </span><span class="pun">`</span><span class="typ">String</span><span class="pun">`</span><span class="pln"> cannot be indexed by </span><span class="pun">`{</span><span class="pln">integer</span><span class="pun">}`</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">13</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let h </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">             </span><span class="pun">^^^^^</span><span class="pln"> </span><span class="pun">`</span><span class="typ">String</span><span class="pun">`</span><span class="pln"> cannot be indexed by </span><span class="pun">`{</span><span class="pln">integer</span><span class="pun">}`</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the trait </span><span class="pun">`</span><span class="typ">Index</span><span class="pun">&lt;{</span><span class="pln">integer</span><span class="pun">}&gt;`</span><span class="pln"> is not implemented </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">`</span><span class="typ">String</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the following other types implement trait </span><span class="pun">`</span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">Idx</span><span class="pun">&gt;`:</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">RangeFrom</span><span class="str">&lt;usize&gt;</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">RangeFull</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">RangeInclusive</span><span class="str">&lt;usize&gt;</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">RangeTo</span><span class="str">&lt;usize&gt;</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="typ">RangeToInclusive</span><span class="str">&lt;usize&gt;</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">String</span><span class="pln"> as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="pln">std</span><span class="pun">::</span><span class="pln">ops</span><span class="pun">::</span><span class="typ">Range</span><span class="str">&lt;usize&gt;</span><span class="pun">&gt;&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">str as </span><span class="typ">Index</span><span class="pun">&lt;</span><span class="pln">I</span><span class="pun">&gt;&gt;</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0277</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">collections</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	تخبرنا رسالة الخطأ بالآتي: لا تدعم السلاسل النصية في رست الفهرسة indexing، ولكن لماذا؟ للإجابة على هذا السؤال دعنا نناقش كيف تخزّن رست السلاسل النصية في الذاكرة.
</p>

<h3>
	التمثيل الداخلي
</h3>

<p>
	النوع <code>String</code> في الحقيقة هو مغلّف حول النوع <code>Vec&lt;u8&gt;‎</code>، دعنا نلقي نظرةً على السلسلة النصية التالية المرمزة بترميز UTF-8 من الشيفرة 14:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_33" style=""><span class="pln">let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Hola"</span><span class="pun">);</span></pre>

<p>
	طول السلسلة النصية <code>len</code> في هذه الحالة هو 4، ما يعني أن الشعاع الذي يخزن السلسلة النصية "Hola" هو بطول 4 بايتات، إذ يأخذ كل حرف من هذه الأحرف 1 بايت عند ترميزه بترميز UTF-8، إلا أن السطر التالي قد يفاجئك (لاحظ أن السلسلة النصية التالية تبدأ بالحرف السيريلي زي Cyrillic letter Ze وليس العدد العربي 3).
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_35" style=""><span class="pln">let hello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Здравствуйте"</span><span class="pun">);</span></pre>

<p>
	إذا سألناك عن طول السلسلة النصية ستجيب غالبًا 12، إلا أن رست ستجيبك بالقيمة 24 وهو رقم البايتات المطلوبة لترميز السلسلة النصية "Здравствуйте" بترميز UTF-8 وذلك لأن كل محرف يونيكود unicode يأخذ 2 بايت للتخزين، ولذلك استخدام دليل إلى بايت السلسلة النصية لن يعمل دومًا، ولتوضيح ذلك ألقِ نظرةً على شيفرة رست التالية غير الصالحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_37" style=""><span class="pln">let hello </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Здравствуйте"</span><span class="pun">;</span><span class="pln">
let answer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">hello</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span></pre>

<p>
	أنت تعلم مسبقًا أن قيمة <code>answer</code> لن تكون الحرف الأول <code>З</code>، إذ تكون قيمة البايت الأول من الحرف <code>3</code> عند ترميز السلسلة النصية بترميز UTF-8 هي <code>208</code> والثاني قيمته 151 وبالتالي ستكون قيمة <code>answer</code> هي <code>208</code> إلا أن القيمة 208 ليست بقيمة صالحة لمحرف، وإعادة القيمة 208 ليست التصرف الذي يترقبه المستخدم غالبًا عند سؤاله عن المحرف الأول من السلسلة النصية، إلا أنها القيمة الوحيدة الموجودة في الدليل 0. لا يريد المستخدمون عادةً الحصول على قيمة البايت حتى لو احتوت السلسلة النصية على أحرف لاتينية، فإذا كانت <code>‎&amp;"hello"[0]‎</code> شيفرة برمجية صالحة، فسيعيد ذلك قيمة البايت الممثلة بالقيمة 104 وليس <code>h</code>.
</p>

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

<h3>
	البايتات والقيم العددية ومجموعات حروف اللغة
</h3>

<p>
	نقطة أخرى يجب ذكرها عن ترميز UTF-8، ألا وهو وجود ثلاث طرق مختلفة للنظر إلى السلاسل النصية من منظور لغة رست: مثل بايتات أو قيم عددية scalar values أو مجموعات قيم عددية grapheme clusters (التمثيل الأقرب لما نسميه نحن البشر بالأحرف).
</p>

<p>
	إذا نظرنا إلى الكلمة الهندية "नमस्ते" المكتوبة بالطريقة الديفاناغارية Devanagari، فهي مُخزّنة على أنها شعاع من نوع <code>u8</code> تبدو قيمه على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_39" style=""><span class="pun">[</span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">164</span><span class="pun">,</span><span class="pln"> </span><span class="lit">168</span><span class="pun">,</span><span class="pln"> </span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">164</span><span class="pun">,</span><span class="pln"> </span><span class="lit">174</span><span class="pun">,</span><span class="pln"> </span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">164</span><span class="pun">,</span><span class="pln"> </span><span class="lit">184</span><span class="pun">,</span><span class="pln"> </span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">165</span><span class="pun">,</span><span class="pln"> </span><span class="lit">141</span><span class="pun">,</span><span class="pln"> </span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">164</span><span class="pun">,</span><span class="pln"> </span><span class="lit">164</span><span class="pun">,</span><span class="pln">
</span><span class="lit">224</span><span class="pun">,</span><span class="pln"> </span><span class="lit">165</span><span class="pun">,</span><span class="pln"> </span><span class="lit">135</span><span class="pun">]</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_42" style=""><span class="pun">[</span><span class="str">'न'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'म'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'स'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'्'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'त'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'े'</span><span class="pun">]</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_44" style=""><span class="pun">[</span><span class="str">"न"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"म"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"स्"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ते"</span><span class="pun">]</span></pre>

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

<p>
	السبب الأخير لكون رست لا تسمح بالوصول إلى النوع <code>String</code> باستخدام الدليل للحصول على محرف معين هو أن عمليات الفهرسة تأخذ تعقيدًا زمنيًا time complexity ثابتًا -مقداره O(1)‎- إلا أنه ليس من الممكن ضمان ذلك الأداء مع النوع <code>String</code> لأن رست ستكون بحاجة للنظر إلى محتويات السلسلة النصية من البداية إلى الدليل المُحدّد لتحديد عدد المحارف الصالحة الموجودة.
</p>

<h2>
	شرائح السلاسل النصية
</h2>

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

<p>
	بدلًا من استخدام الأقواس <code>[]</code> مع رقم وحيد، يمكنك استخدام الأقواس <code>[]</code> لتحديد نطاق معين يحتوي على الشريحة النصية بعدد محدد من البايتات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_46" style=""><span class="pln">let hello </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Здравствуйте"</span><span class="pun">;</span><span class="pln">

let s </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">hello</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="lit">4</span><span class="pun">];</span></pre>

<p>
	ستكون <code>s</code> هنا هي <code>str&amp;</code> تحتوي على أول 4 بايتات من السلسلة. ذكرنا سابقًا أن كل حرف من هذه الأحرف هو بحجم 2 بايت، وهذا يعني أن <code>s</code> ستكون "Зд".
</p>

<p>
	إذا حاولنا تقسيم جزء واحد من بايتات المحرف مثل <code>[hello[0..1&amp;</code>، ستصاب رست بالهلع أثناء التشغيل بنفس الطريقة التي تحدث عند الوصول إلى دليل غير صالح في شعاعٍ ما، كما هو موضح في الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_48" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> collections v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/collections)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.43s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">collections</span><span class="pun">`</span><span class="pln">
thread </span><span class="str">'main'</span><span class="pln"> panicked at </span><span class="str">'byte index 1 is not a char boundary; it is inside '</span><span class="pun">З</span><span class="str">' (bytes 0..2) of `Здравствуйте`'</span><span class="pun">,</span><span class="pln"> library</span><span class="pun">/</span><span class="pln">core</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="pln">str</span><span class="pun">/</span><span class="pln">mod</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">127</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> run with </span><span class="pun">`</span><span class="pln">RUST_BACKTRACE</span><span class="pun">=</span><span class="lit">1</span><span class="pun">`</span><span class="pln"> environment variable to display a backtrace</span></pre>

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

<h2>
	توابع التكرار على السلاسل النصية
</h2>

<p>
	أفضل طريقة للعمل على قطع pieces من السلاسل النصية هي أن تكون واضحًا فيما إذا كنت تريد أحرفًا أم بايتات، فمن أجل قيم عددية مفردة مُرمزة بالترميز الموحد يونيكود Unicode، استخدم التابع <code>chars</code>، إذ أن استدعاء هذا التابع على السلسلة "Зд" سيفصل المحرفين ويعيد قيمتان من النوع <code>char</code>، ويمكنك تكرار النتيجة للوصول إلى كل عنصر لوحده:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_50" style=""><span class="com">#![allow(unused)]</span><span class="pln">
fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> c in </span><span class="str">"Зд"</span><span class="pun">.</span><span class="pln">chars</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{}"</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>
	ستطبع الشيفرة البرمجية ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_52" style=""><span class="pun">З</span><span class="pln">
</span><span class="pun">д</span></pre>

<p>
	يمكننا استخدام التابع <code>bytes</code> بديلًا عمّا سبق وهو تابع يُعيد كل بايتًا كاملًا، إلا أنه قد يكون غير مناسبًا لاستخدامك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8852_56" style=""><span class="kwd">for</span><span class="pln"> b in </span><span class="str">"Зд"</span><span class="pun">.</span><span class="pln">bytes</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> b</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_8852_58" style=""><span class="lit">208</span><span class="pln">
</span><span class="lit">151</span><span class="pln">
</span><span class="lit">208</span><span class="pln">
</span><span class="lit">180</span></pre>

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

<p>
	الحصول على مجموعة حروف لغة من السلاسل النصية كما حدث في مثال الأحرف الديفاناغارية غير موجود في المكتبة القياسية لأنه معقّد، إلا أن هناك العديد من الصناديق crates <a href="https://crates.io/" rel="external nofollow">crates.io</a> التي تساعدك للحصول على النتيجة المرجوة.
</p>

<h2>
	السلاسل النصية ليست بسيطة
</h2>

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

<p>
	الخبر الجيد هنا هو أن المكتبة القياسية تقدم العديد من المزايا المبنية على كل من النوعين <code>String</code> و <code>‎&amp;str</code> لمساعدتنا في التعامل مع الحالات المعقدة بصورةٍ صحيحة. ألقِ نطرةً على التوثيق في حال أردت استخدام توابع مفيدة مثل <code>contains</code> للبحث في سلسلة نصية و <code>replace</code> لاستبدال أجزاء من السلسلة النصية بسلسلة نصية أخرى.
</p>

<p>
	دعنا ننتقل إلى شيء أقل تعقيدًا، ألا وهو الخرائط المُعمّاة Hash maps.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html" rel="external nofollow">Common Collections</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%86%D9%88%D8%B9-hashmap-%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1917/" rel="">كيفية استخدام النوع HashMap لتخزين البيانات في رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D9%84%D8%A7%D8%A6%D8%AD%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D9%82%D9%8A%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D8%B9%D8%A9-vectors-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1875/" rel="">تخزين لائحة من القيم باستخدام الأشعة Vectors في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">كيفية كتابة الدوال Functions والتعليقات Comments في لغة راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1876</guid><pubDate>Thu, 23 Feb 2023 16:05:00 +0000</pubDate></item><item><title>&#x62A;&#x62E;&#x632;&#x64A;&#x646; &#x644;&#x627;&#x626;&#x62D;&#x629; &#x645;&#x646; &#x627;&#x644;&#x642;&#x64A;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x623;&#x634;&#x639;&#x629; Vectors &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D9%84%D8%A7%D8%A6%D8%AD%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D9%82%D9%8A%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D8%B9%D8%A9-vectors-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1875/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/468460602_------vector----Rust.png.24e17dfec89176974098d5cc26769418.png" /></p>
<p>
	سننظر أولًا إلى نوع التجميعة <code>Vec&lt;T&gt;‎</code>، المعروف أيضًا باسم الشعاع vector، إذ تسمح لك الأشعة بتخزين أكثر من قيمة واحدة في هيكل بيانات واحد يضع القيم على نحوٍ متتالي في الذاكرة، ويمكن أن تخزن الأشعة قيمًا من النوع ذاته، وهي مفيدةٌ عندما يكون لديك لائحةٌ من العناصر، مثل سطور نصية ضمن ملف، أو أسعار منتجات في سلة تسوّق.
</p>

<h2>
	إنشاء شعاع جديد
</h2>

<p>
	لإنشاء شعاع جديد فارغ نستدعي الدالة <code>Vec::new</code> كما هو موضح في الشيفرة 1.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_8" style=""><span class="pln">let v</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Vec</span><span class="str">&lt;i32&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Vec</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span></pre>

<p style="text-align: center;">
	الشيفرة 1: إنشاء شعاع جديد فارغ لتخزين قيم من النوع i32
</p>

<p>
	لاحظ أننا كتبنا ما يشير إلى <a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">نوع البيانات</a>، لأننا لا نستطيع إدخال أي نوع نريده في الشعاع، ويجب على <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> أن تعلم أي نوع من البيانات نريد أن ندخله إلى الشعاع، وهذه النقطة مهمة جدًا. بُنيَت الأشعة باستخدام الأنواع المعمّاة generics وسنغطّي استخدام الأنواع المعمّاة مع أنواعك الخاصة لاحقًا، ويكفي حاليًا أن تعرف أن النوع <code>Vec&lt;T&gt;‎</code> الموجود في المكتبة القياسية يستطيع تخزين أي نوع داخله. يمكننا تحديد النوع الذي يحمله الشعاع عند إنشائه دون استخدام الأقواس المثلثة angle brackets. أخبرنا راست في الشيفرة 1 أن <code>Vec&lt;T&gt;‎</code> في <code>v</code> يحمل عناصر من النوع <code>i32</code>.
</p>

<p>
	ستُنشئ معظم الأحيان شعاع <code>Vec&lt;T&gt;‎</code> يحتوي على قيم ابتدائية ويستنتج رست نوع البيانات التي تريد أن تخزنها داخل الشعاع من القيم الابتدائية، لذا يُعد استخدام الطريقة السابقة نادرًا. توفر لنا رست الماكرو <code>vec!‎</code> الذي يُنشئ شعاعًا جديدًا يحتوي على القيم التي تمررها له، وتوضح الشيفرة 2 ذلك بإنشاء شعاع من النوع <code>Vec&lt;i32&gt;‎</code> يحتوي على القيم 1 و2 و3، والنوع هو <code>i32</code> لأنه النوع الافتراضي للأعداد الصحيحة كما ناقشنا سابقًا في مقال أنواع البيانات.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_10" style=""><span class="pln">let v </span><span class="pun">=</span><span class="pln"> vec</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></pre>

<p style="text-align: center;">
	الشيفرة 2: إنشاء شعاع جديد يحتوي على قيم
</p>

<p>
	تستطيع رست استنتاج أن نوع الشعاع <code>v</code> هو <code>Vec&lt;i32&gt;‎</code>، لأننا أعطينا قيمًا ابتدائية من النوع <code>i32</code>، وكتابة النوع مباشرةً ليس ضروريًا هنا. الآن دعنا ننظر إلى كيفية التعديل على شعاع.
</p>

<h2>
	تحديث شعاع
</h2>

<p>
	يمكننا استخدام التابع <code>push</code> لإضافة عناصر إلى شعاع بعد إنشائه كما هو موضح في الشيفرة 3.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_12" style=""><span class="pln">    let mut v </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Vec</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
    v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">6</span><span class="pun">);</span><span class="pln">
    v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">7</span><span class="pun">);</span><span class="pln">
    v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 3: استخدام التابع push لإضافة قيم إلى شعاع
</p>

<p>
	إذا أردنا تغيير القيم، علينا أن نجعل الشعاع قابلًا للتعديل -كما هو الحال مع أي <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">متغير</a> اعتيادي- باستخدام الكلمة المفتاحية <code>mut</code> كما ناقشنا سابقًا. جميع الأرقام التي وضعناها في الشعاع هي من النوع <code>i32</code>، وتستنتج رست ذلك من البيانات، لذلك ليس من الضروري تحديد النوع بكتابة <code>Vec&lt;i32&gt;‎</code>.
</p>

<h2>
	قراءة العناصر من الأشعة
</h2>

<p>
	هناك طريقتان للإشارة إلى قيمة موجودة في الشعاع: إما باستخدام الدليل index أو باستخدام التابع <code>get</code>، نوضح في الأمثلة التالية أنواع البيانات التي تُعيدها <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">الدوال</a> بهدف جعلها واضحةً قدر الإمكان.
</p>

<p>
	توضح الشيفرة 4 كلا الطريقتين في الوصول إلى قيمة ضمن شعاع، وذلك باستخدام دليل العنصر أو التابع <code>get</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_14" style=""><span class="pln">    let v </span><span class="pun">=</span><span class="pln"> vec</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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

    let third</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">i32 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">v</span><span class="pun">[</span><span class="lit">2</span><span class="pun">];</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The third element is {}"</span><span class="pun">,</span><span class="pln"> third</span><span class="pun">);</span><span class="pln">

    let third</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Option</span><span class="pun">&lt;&amp;</span><span class="pln">i32</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> v</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">
    match third </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">third</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"The third element is {}"</span><span class="pun">,</span><span class="pln"> third</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">None</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"There is no third element."</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 4: استخدام دليل العنصر أو التابع get للحصول على عنصر ضمن الشعاع
</p>

<p>
	لاحظ بعض التفاصيل المهمة هنا؛ إذ استخدمنا قيمة الدليل "2" للحصول على العنصر الثالث وذلك لأن العناصر في الشعاع تحمل دليل عددي يبدأ من الصفر، كما يعطي استخدام <code>&amp;</code> و<code>[]</code> مرجعًا إلى العنصر الموجود في الدليل الذي حددناه. عندما نستخدم التابع <code>get</code> مع تمرير الدليل مثل وسيط argument نحصل على <code>Option&lt;&amp;T&gt;‎</code> الذي يمكننا استخدامه مع البنية <code>match</code>.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_16" style=""><span class="pln">    let v </span><span class="pun">=</span><span class="pln"> vec</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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

    let does_not_exist </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">v</span><span class="pun">[</span><span class="lit">100</span><span class="pun">];</span><span class="pln">
    let does_not_exist </span><span class="pun">=</span><span class="pln"> v</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">100</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 5: محاولة الوصول إلى الدليل 100 في شعاع يحتوي على خمسة عناصر فقط
</p>

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

<p>
	عندما نمرر إلى التابع <code>get</code> دليلًا يقع خارج المصفوفة فهو يُعيد القيمة <code>None</code> دون الهلع، ويجب أن تستخدم هذه الطريقة إذا كانت محاولة الوصول إلى عنصر يقع خارج نطاق الشعاع ممكنة الحدوث تحت الظروف الاعتيادية، ويجب على برنامجك عندها أن يتعامل مع <code>Some(&amp;element)‎</code> أو <code>None</code> كما ناقشنا سابقًا. على سبيل المثال، قد يكون الدليل مُدخلًا من قِبل المستخدم وبالتالي إذا أدخل المستخدم رقمًا أكبر من حجم الشعاع عن طريق الخطأ نحصل على القيمة <code>None</code> ويمكنك إخبار المستخدم عندها أن الرقم الذي أدخله كبير ويمكن إعلامه أيضًا بحجم الشعاع الحالي وإعادة طلب إدخال القيمة منه، وهذه وسيلة عملية أكثر من جعل البرنامج يتوقف بالكامل بسبب خطأ كتابي بسيط
</p>

<p>
	عندما نحصل على مرجع صالح، يتأكد مدقق الاستعارة borrow checker من أن قوانين <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية ownership</a> و<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">الاستعارة borrowing</a> محققة (ناقشنا هذه القوانين <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">سابقًا</a>) للتأكد من أن المرجع وأي <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">مراجع</a> أخرى لمحتوى الشعاع هي مراجع صالحة. تذكر القاعدة التي تنص على أنه لا يمكنك الحصول على مرجع قابل للتعديل ومرجع آخر غير قابل للتعديل في النطاق ذاته، وتنطبق هذه القاعدة على الشيفرة 6 عندما نخزن مرجعًا غير قابلٍ للتعديل للعنصر الأول في الشعاع ومن ثم نجرّب إضافة عنصر إلى نهاية الشعاع، ولن يعمل هذا البرنامج إذا أردنا الإشارة إلى ذلك العنصر لاحقًا ضمن الدالة ذاتها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_18" style=""><span class="pln">    let mut v </span><span class="pun">=</span><span class="pln"> vec</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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

    let first </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">v</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">

    v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">6</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The first element is: {}"</span><span class="pun">,</span><span class="pln"> first</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	الشيفرة 6: محاولة إضافة عنصر إلى شعاع مع تخزين مرجع إلى عنصر داخل الشعاع في الوقت ذاته
</p>

<p>
	سيتسبب تصريف الشيفرة البرمجية السابقة بالخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_20" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> collections v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/collections)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0502</span><span class="pun">]:</span><span class="pln"> cannot borrow </span><span class="pun">`</span><span class="pln">v</span><span class="pun">`</span><span class="pln"> as </span><span class="kwd">mutable</span><span class="pln"> because it is also borrowed as immutable
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">6</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let first </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">v</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                  </span><span class="pun">-</span><span class="pln"> immutable borrow occurs here
</span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     v</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">6</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">     </span><span class="pun">^^^^^^^^^</span><span class="pln"> </span><span class="kwd">mutable</span><span class="pln"> borrow occurs here
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     println</span><span class="pun">!(</span><span class="str">"The first element is: {}"</span><span class="pun">,</span><span class="pln"> first</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                                          </span><span class="pun">-----</span><span class="pln"> immutable borrow later used here

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0502</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">collections</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<p>
	<strong>ملاحظة</strong>: للمزيد من التفاصيل حول النوع <code>Vec&lt;T&gt;‎</code> ألقِ نظرةً على إلى مثال عن تنفيذ Vec<a href="https://doc.rust-lang.org/stable/nomicon/vec/vec.html" rel="external nofollow"> Rustonomicon</a>.
</p>

<h2>
	الوصول إلى قيم شعاع متعاقبة
</h2>

<p>
	للوصول إلى عناصر الشعاع بصورةٍ متعاقبة، نمرّ بجميع العناصر الموجودة دون الحاجة لاستخدام دليل كل عنصر في كل مرة، وتوضح الشيفرة 7 كيفية استخدام الحلقة <code>for</code> للحصول على مراجع غير قابلة للتعديل لعناصر الشعاع من النوع <code>i32</code> وطباعتها.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_22" style=""><span class="pln">    let v </span><span class="pun">=</span><span class="pln"> vec</span><span class="pun">![</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">];</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i in </span><span class="pun">&amp;</span><span class="pln">v </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 7: طباعة كل عنصر في شعاع عن طريق المرور على العناصر باستخدام حلقة for
</p>

<p>
	يمكننا أيضًا المرور على مراجع قابلة للتعديل mutable لكل عنصر في شعاع قابل للتعديل، وذلك بهدف إجراء تغييرات على جميع العناصر. تجمع الحلقة <code>for</code> في الشيفرة 8 القيمة 50 إلى كل عنصر في الشعاع.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_24" style=""><span class="pln">    let mut v </span><span class="pun">=</span><span class="pln"> vec</span><span class="pun">![</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln"> </span><span class="lit">57</span><span class="pun">];</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i in </span><span class="pun">&amp;</span><span class="pln">mut v </span><span class="pun">{</span><span class="pln">
        </span><span class="pun">*</span><span class="pln">i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 8: المرور على مراجع قابلة للتعديل لعناصر في شعاع
</p>

<p>
	لتغيير قيمة العنصر الذي يشير المرجع القابل للتعديل إليه نستخدم عامل التحصيل dereference <code>*</code> للحصول على القيمة الموجودة في <code>i</code> قبل استخدام العامل <code>=+</code>، وسنناقش عامل التحصيل بتوسع أكبر لاحقًا.
</p>

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

<h2>
	استخدام تعداد لتخزين عدة أنواع
</h2>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_26" style=""><span class="pln">    </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">SpreadsheetCell</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Int</span><span class="pun">(</span><span class="pln">i32</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Float</span><span class="pun">(</span><span class="pln">f64</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Text</span><span class="pun">(</span><span class="typ">String</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let row </span><span class="pun">=</span><span class="pln"> vec</span><span class="pun">![</span><span class="pln">
        </span><span class="typ">SpreadsheetCell</span><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="typ">SpreadsheetCell</span><span class="pun">::</span><span class="typ">Text</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"blue"</span><span class="pun">)),</span><span class="pln">
        </span><span class="typ">SpreadsheetCell</span><span class="pun">::</span><span class="typ">Float</span><span class="pun">(</span><span class="lit">10.12</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">];</span></pre>

<p style="text-align: center;">
	الشيفرة 9: تعريف تعداد enum لتخزين قيم من أنواع مختلفة في شعاع واحد
</p>

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

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

<p>
	الآن، وبعد أن ناقشنا أكثر الطرق شيوعًا في استخدام الأشعة، ألقِ نظرةً على <a href="https://doc.rust-lang.org/stable/std/vec/struct.Vec.html" rel="external nofollow">توثيق الواجهة البرمجية</a> للمزيد من <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">التوابع </a>المفيدة المعرفة في النوع <code>&lt;Vec&lt;T</code> في المكتبة القياسية، على سبيل المثال، بالإضافة إلى تابع <code>push</code>، هناك تابع <code>pop</code> لحذف وإعادة العنصر الأخير ضمن الشعاع.
</p>

<h2>
	التخلص من الشعاع يعني التخلص من عناصره
</h2>

<p>
	يُحرَّر الشعاع من الذاكرة مثل أيّ هيكل <code>struct</code> اعتيادي عند خروجه من النطاق كما هو موضح في الشيفرة 10.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1935_28" style=""><span class="pln">    </span><span class="pun">{</span><span class="pln">
        let v </span><span class="pun">=</span><span class="pln"> vec</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="lit">4</span><span class="pun">];</span><span class="pln">

        </span><span class="com">// استخدام‫ v</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// تخرج‫ ‎‎ v من النطاق وتُحرَّر من الذاكرة بحلول هذه النقطة</span></pre>

<p style="text-align: center;">
	الشيفرة 10: توضيح النقطة التي يُحرَّر فيها الشعاع ونفقد عناصره
</p>

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

<p>
	دعنا ننتقل إلى نوع التجميعة التالي: ألا وهو السلسلة النصية <code>String</code>.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch08-00-common-collections.html" rel="external nofollow">Common Collections</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A8%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-utf-8-%D8%AF%D8%A7%D8%AE%D9%84-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1876/" rel="">تخزين النصوص بترميز UTF-8 داخل السلاسل النصية في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5-%D8%A8%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1874/" rel="">المسارات paths والنطاق الخاص بها في لغة رست </a><a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5-%D8%A8%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1874/" rel="">Rust</a><a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel=""> </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel="">بنية match للتحكم بسير برامج لغة رست </a> <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel="">Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/" rel="">التعدادات enums في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1875</guid><pubDate>Thu, 16 Feb 2023 16:04:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x633;&#x627;&#x631;&#x627;&#x62A; paths &#x648;&#x627;&#x644;&#x646;&#x637;&#x627;&#x642; &#x627;&#x644;&#x62E;&#x627;&#x635; &#x628;&#x647;&#x627; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5-%D8%A8%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1874/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/338481273_-paths--scope------Rust.png.301660c3d3ec5f535cf6b9eff90ca0e2.png" /></p>
<p>
	قد تكون عملية كتابة مسارات استدعاء <span ipsnoautolink="true">الدوال</span> في بعض الأحيان عملية غير مريحة ورتيبة، كان علينا في الشيفرة 7 (سابقًا) تحديد <code>front_of_house</code> و <code>hosting</code> في حال اخترنا المسار النسبي relative path أو المسار المطلق absolute path إلى الدالة <code>add_to_waitlist</code> وفي كل مرة أردنا استدعاء الدالة <code>add_to_waitlist</code> أيضًا. لحسن الحظ هناك طريقة لتبسيط العملية السابقة، إذ يمكننا إنشاء اختصار للمسار باستخدام الكلمة المفتاحية <code>use</code> مرةً واحدةً فقط ومن ثمّ استخدام المسار الأقصر المُختصر في كل مكان ضمن النطاق.
</p>

<p>
	نُضيف الوحدة <code>crate::front_of_house::hosting</code> إلى نطاق دالة <code>eat_at_restaurant</code> في الشيفرة 11، وذلك حتى نكتفي بكتابة <code>hosting::add_to_waitlist</code> لاستدعاء الدالة <code>add_to_waitlist</code> في <code>eat_at_restaurant</code>.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_10" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        pub fn add_to_waitlist</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">

use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">;</span><span class="pln">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 11: إضافة الوحدة إلى النطاق باستخدام use
</p>

<p>
	تُعد عملية إضافة <code>use</code> متبوعةً بالمسار في النطاق عمليةً مشابهةً لإنشاء رابط رمزي symbolic link في نظام الملفات، إذ يصبح <code>hosting</code> اسمًا صالحًا بإضافة <code>use crate::front_of_house::hosting</code> في جذر الوحدة المصرّفة وضمن ذلك النطاق وكأن الوحدة <code>hosting</code> معرفةٌ داخل جذر الوحدة المصرّفة. تتبع المسارات الموجودة ضمن النطاق باستخدام <code>use</code> قوانين الخصوصية مثلها مثل أي مسار آخر.
</p>

<p>
	لاحظ أن <code>use</code> يُنشئ اختصارًا للنطاق الذي يحتوي على <code>use</code> فقط. ننقل في الشيفرة 12 الدالة <code>eat_at_restaurant</code> إلى وحدة ابن جديدة تدعى <code>customer</code> وهي ذات نطاق مختلف عن تعليمة <code>use</code>، لذا لن نستطيع تصريف محتوى الدالة:
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_12" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        pub fn add_to_waitlist</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">

use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">;</span><span class="pln">

mod customer </span><span class="pun">{</span><span class="pln">
    pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 12: تعليمة use تُطبّق فقط في النطاق الواردة فيها
</p>

<p>
	يوضح خطأ التصريف التالي أن الاختصار غير موجود ضمن الوحدة <code>customer</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_14" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> restaurant v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/restaurant)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0433</span><span class="pun">]:</span><span class="pln"> failed to resolve</span><span class="pun">:</span><span class="pln"> use of undeclared crate or module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">11</span><span class="pun">:</span><span class="lit">9</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">11</span><span class="pln"> </span><span class="pun">|</span><span class="pln">         hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">         </span><span class="pun">^^^^^^^</span><span class="pln"> use of undeclared crate or module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln">

warning</span><span class="pun">:</span><span class="pln"> unused </span><span class="kwd">import</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">7</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</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"> note</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`#[</span><span class="pln">warn</span><span class="pun">(</span><span class="pln">unused_imports</span><span class="pun">)]`</span><span class="pln"> on by </span><span class="kwd">default</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0433</span><span class="pun">`.</span><span class="pln">
warning</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">restaurant</span><span class="pun">`</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lib</span><span class="pun">)</span><span class="pln"> generated </span><span class="lit">1</span><span class="pln"> warning
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">restaurant</span><span class="pun">`</span><span class="pln"> due to previous error</span><span class="pun">;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> warning emitted</span></pre>

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

<h2>
	إنشاء مسارات اصطلاحية Idiomatic باستخدام use
</h2>

<p>
	لعلّك تساءلت عند قراءتك للشيفرة 11 عن سبب كتابتنا <code>use crate::front_of_house::hosting</code> ومن ثم استدعائنا <code>hosting::add_to_waitlist</code> في <code>eat_at_restaurant</code> بدلًا من تحديد مسار <code>use</code> الموجود في الدالة <code>add_to_waitlist</code> لتحقيق النتيجة ذاتها كما هو الأمر في الشيفرة 13.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_16" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        pub fn add_to_waitlist</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">

use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">;</span><span class="pln">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 13: إضافة الدالة add_to_waitlist إلى النطاق باستخدام use وهو استخدام غير اصطلاحي unidiomatic
</p>

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

<p>
	على الجانب الآخر، عند إضافة <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%84%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%B1%D8%B3%D8%AA-rust-r1849/" rel="">الهياكل</a> و<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/" rel="">التعدادات</a> والعناصر الأخرى إلى النطاق باستخدام <code>use</code> فإن الاستخدام الاصطلاحي هو تحديد كامل المسار، وتوضح الشيفرة 14 الطريقة الاصطلاحية في إضافة الهيكل <code>HashMap</code> الموجود في المكتبة القياسية إلى نطاق الوحدة الثنائية المُصرّفة.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_18" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut </span><span class="typ">map</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">map</span><span class="pun">.</span><span class="pln">insert</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></pre>

<p style="text-align: center;">
	الشيفرة 14: إضافة HashMap إلى النطاق بطريقة اصطلاحية
</p>

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

<p>
	الاستثناء لهذا الاصطلاح هو حالة إضافة عنصرين إلى النطاق يحملان الاسم ذاته باستخدام تعليمة <code>use</code>، إذ لا تسمح <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> بذلك. توضح الشيفرة 15 كيفية إضافة نوعَي <code>Result</code> إلى النطاق يحملان الاسم ذاته ولكنهما ينتميان إلى وحدات أب مختلفة، إضافةً إلى كيفية الإشارة إليهما.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_20" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">fmt</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn function1</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> fmt</span><span class="pun">::</span><span class="typ">Result</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
    </span><span class="typ">Ok</span><span class="pun">(())</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn function2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> io</span><span class="pun">::</span><span class="typ">Result</span><span class="pun">&lt;()&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
    </span><span class="typ">Ok</span><span class="pun">(())</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 15: إضافة نوعين من الاسم ذاته إلى النطاق ذاته يتطلب استخدام الوحدات الأب
</p>

<p>
	كما تلاحظ، يميز استخدام الوحدات الأب ما بين النوعين <code>Result</code>، وإذا استخدمنا <code>use std::fmt::Result</code> و <code>use std::io::Result</code> بدلًا من ذلك فسيكون لدينا قيمتين <code>Result</code> في نفس النطاق، ولن تعرف رست عندها أي الأنواع التي نقصدها عندما نستخدم <code>Result</code>.
</p>

<h2>
	إضافة أسماء جديدة باستخدام الكلمة المفتاحية as
</h2>

<p>
	هناك حل آخر لمشكلة إضافة نوعين من الاسم ذاته إلى النطاق باستخدام <code>use</code>، إذ يمكننا كتابة الكلمة المفتاحية <code>as</code> بعد المسار وكتابة اسم محلي بعدها أو اسم مستعار alias للنوع. توضح الشيفرة 16 طريقةً أخرى لكتابة الشيفرة 15 بإعادة تسمية واحد من النوعَين <code>Result</code> باستخدام <code>as</code>.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_24" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">fmt</span><span class="pun">::</span><span class="typ">Result</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">::</span><span class="typ">Result</span><span class="pln"> as </span><span class="typ">IoResult</span><span class="pun">;</span><span class="pln">

fn function1</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
    </span><span class="typ">Ok</span><span class="pun">(())</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn function2</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">IoResult</span><span class="pun">&lt;()&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
    </span><span class="typ">Ok</span><span class="pun">(())</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 16: إعادة تسمية نوع بعد إضافته إلى النطاق باستخدام الكلمة المفتاحية as
</p>

<p>
	اخترنا في تعليمة <code>use</code> الثانية الاسم الجديد <code>IoResult</code> للنوع <code>std::io::Result</code> وهو اسم لا يتعارض مع الاسم <code>Result</code> في <code>std::fmt</code> الذي أضفناه إلى النطاق أيضًا. تعدّ كلًا من الشيفرة 15 والشيفرة 16 طريقةً اصطلاحيةً في التغلب على مشكلة تعارض الأسماء، فاختر ما يحلو لك.
</p>

<h2>
	إعادة تصدير الأسماء باستخدام pub use
</h2>

<p>
	عندما نُضيف اسمًا إلى النطاق باستخدام الكلمة المفتاحية <code>use</code>، سيكون هذا الاسم المتاح في النطاق الجديد خاصًا. لتمكين الشيفرة البرمجية التي تستدعي الشيفرة البرمجية لتُشير إلى ذلك الاسم وكأنه معرّف في نطاق الشيفرة البرمجية تلك، علينا استخدام <code>pub</code> مع <code>use</code>، وتُعرف هذه الطريقة باسم إعادة التصدير re-exporting لأننا نُضيف العنصر إلى النطاق، لكننا نجعله ممكن الإضافة لنطاقات أخرى.
</p>

<p>
	تمثل الشيفرة 17 نسخةً معدلةً عن الشيفرة 11 بتغيير استخدام <code>use</code> في الوحدة الجذر إلى <code>pub use</code>.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_26" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        pub fn add_to_waitlist</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">

pub use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">;</span><span class="pln">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 17: جعل الاسم متاحًا لأي شيفرة برمجية لاستخدامه من نطاق جديد باستخدام pub use
</p>

<p>
	كان على الشيفرة البرمجية الخارجية -قبل هذا التغيير- استدعاء الدالة <code>add_to_waitlist</code> باستخدام المسار <code>restaurant:: front_of_house::hosting::add_to_waitlist()‎</code>، والآن وبعد إعادة تصدير وحدة <code>hosting</code> باستخدام <code>pub use</code> من الوحدة الجذر يُمكن للشيفرة الخارجية الآن أن تستخدم المسار <code>restaurant::hosting::add_to_waitlist()‎</code>.
</p>

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

<h2>
	استخدام الحزم الخارجية
</h2>

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

<p>
	اسم الملف: Cargo.toml
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_28" style=""><span class="pln">rand </span><span class="pun">=</span><span class="pln"> </span><span class="str">"0.8.3"</span></pre>

<p>
	تخبر إضافة <code>rand</code> مثل اعتمادية dependency في ملف Cargo.toml كارجو بأنه يجب عليه تنزيل الحزمة <code>rand</code> وأي اعتمادية من <a href="https://crates.io/" rel="external nofollow">crates.io</a> وجعل الحزمة <code>rand</code> متاحة في مشروعنا.
</p>

<p>
	أضفنا السطر <code>use</code> مع اسم الوحدة المُصرّفة لجلب التعاريف الموجودة في الحزمة <code>rand</code> إلى نطاق حزمتنا، وأضفنا العناصر التي أردنا إضافتها إلى النطاق. تذكر أننا أضفنا السمة <code>Rng</code> إلى نطاقنا واستدعينا الدالة <code>rand::thread_rng</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_30" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كتب الكثير من أعضاء مجتمع رست حزمًا وجعلها متاحة على <a href="https://crates.io/" rel="external nofollow">crates.io</a>، ويجب أن تتبع هذه الخطوات إذا أردت استخدام أي منها: إضافة الحزم في الملف Cargo.toml مثل قائمة، واستخدام <code>use</code> لإضافة العناصر من وحداتها المُصرّفة إلى النطاق.
</p>

<p>
	لاحظ أن المكتبة القياسية <code>std</code> هي في الحقيقة وحدة مُصرَّفة خارجية لحزمتنا، وليس علينا تغيير الملف Cargo.toml لتضمين <code>std</code> لأن المكتبة القياسية تُضاف افتراضيًا إلى مشروعنا<a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel=""> بلغة رست</a>، إلا أننا بحاجة إضافة عناصرها إلى نطاق حزمتنا باستخدام <code>use</code>. على سبيل المثال، يجب علينا كتابة السطر البرمجي التالي لاستخدام <code>HashMap</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_32" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::</span><span class="typ">HashMap</span><span class="pun">;</span></pre>

<p>
	وهذا يمثّل مسار مطلق يبدأ بالكلمة <code>std</code> وهو اسم وحدة مكتبة مُصرَّفة قياسي.
</p>

<h2>
	استخدام المسارات المتداخلة لتنظيم تعليمات use الطويلة
</h2>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_34" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_36" style=""><span class="pln">use std</span><span class="pun">::{</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">,</span><span class="pln"> io</span><span class="pun">};</span></pre>

<p style="text-align: center;">
	الشيفرة 18: تحديد مسار متداخل لإضافة عدة عناصر إلى النطاق باستخدام مسار مشترك
</p>

<p>
	يُقلّل استخدام المسارات المشتركة عدد السطور اللازمة لإضافة بعض العناصر باستخدام تعليمة <code>use</code> في البرامج الكبيرة بصورةٍ ملحوظة.
</p>

<p>
	يمكننا استخدام المسار المتداخل ضمن أي مستوى في المسار، وهو أمر مفيد عند دمج تعليمتَي <code>use</code> تتشاركان بمسار جزئي. توضح الشيفرة 19 مثلًا تعليمتَي <code>use</code>: أحدها تُضيف <code>std::io</code> إلى النطاق والأخرى تجلب <code>std::io::Write</code> إلى النطاق.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_38" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">::</span><span class="typ">Write</span><span class="pun">;</span></pre>

<p style="text-align: center;">
	الشيفرة 19: تعليمتَي use، تشكًل واحدة منهما مسارًا جزئيًا للآخر
</p>

<p>
	الجزء المشترك من المسارَين هو <code>std::io</code> وهذا هو المسار الكامل الأول، ولدمج المسارَين إلى تعليمة <code>use</code> واحدة يمكننا استخدام <code>self</code> في المسار المتداخل كما هو موضح في الشيفرة 20.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_40" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">::{</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Write</span><span class="pun">};</span></pre>

<p style="text-align: center;">
	الشيفرة 20: دمج المسارَين في الشيفرة 19 إلى تعليمة use واحدة
</p>

<p>
	يُضيف السطر البرمجي السابق كلًا من <code>std::io</code> و <code>std::io::Write</code> إلى النطاق.
</p>

<h2>
	عامل تحديد الكل glob
</h2>

<p>
	يمكننا استخدام العامل <code>*</code> إذا أردنا إضافة جميع العناصر العلنية الموجودة في مسار ما إلى النطاق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_42" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">collections</span><span class="pun">::*;</span></pre>

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

<p>
	يُستخدم عامل تحديد الكل غالبًا عند تجربة إضافة كل شيء ضمن عملية تجربة إلى الوحدة <code>tests</code>، وسنتكلم لاحقًا عن كيفية كتابة هذا النوع من الوحدات. يُستخدم عامل تحديد الكل أيضًا في بعض الأحيان جزءًا من النمط التمهيدي prelude pattern، ألقِ نظرةً على <a href="https://doc.rust-lang.org/stable/std/prelude/index.html#other-preludes" rel="external nofollow">توثيق المكتبة القياسية</a> لمزيد من التفاصيل حول هذا النمط.
</p>

<h2>
	فصل الوحدات إلى ملفات مختلفة
</h2>

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

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

<p>
	دعنا نستخرج أولًا الوحدة <code>front_of_house</code> إلى ملفها الخاص، ونحذف الشيفرة البرمجية داخل الأقواس المعقوصة الخاصة بالوحدة <code>front_of_house</code> ونترك فقط تصريح <code>;mod front_of_house</code>، بحيث يحتوي src/lib.rs على الشيفرة البرمجية الموضحة في الشيفرة 21، ولاحظ أن الشيفرة لن تُصرَّف حتى نُنشئ ملف src/front_of_house.rs، وهو ما سنفعله في الشيفرة 22.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_44" style=""><span class="pln">mod front_of_house</span><span class="pun">;</span><span class="pln">

pub use crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">;</span><span class="pln">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 21: تصريح الوحدة front_of_house التي سيتواجد محتواها في الملف src/front_of_house.rs
</p>

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

<p>
	اسم الملف: src/front_of_house.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_46" style=""><span class="pln">pub mod hosting </span><span class="pun">{</span><span class="pln">
    pub fn add_to_waitlist</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	الشيفرة 22: التعريف داخل الوحدة front_house ضمن الملف src/front_of_house.rs
</p>

<p>
	لاحظ أنك تستطيع تحميل ملف ما باستخدام تصريح <code>mod</code> مرةً واحدةً فقط ضمن شجرة الوحدة، وحالما يعلم المصرف أن هذا الملف ينتمي إلى المشروع (بالإضافة إلى معرفته لمكان الملف ضمن شجرة الوحدة بفضل المكان الذي كتبت فيه تعليمة <code>mod</code>)، ويجب أن تشير الملفات الأخرى إلى الشيفرة البرمجية الخاصة بالملف المُحمّل باستخدام مسار يشير إلى مكان التصريح عنه كما ناقشنا في الفقرات السابقة. بكلمات أخرى، لا تشبه <code>mod</code> عملية تضمين "include"، الموجودة في بعض <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> الأخرى.
</p>

<p>
	الآن، نستخرج الوحدة <code>hosting</code> إلى ملفها الخاص، إلا أن العملية مختلفة هنا بعض الشيء لأن <code>hosting</code> هي وحدة ابن من الوحدة <code>front_of_house</code> وليس وحدة ابن من الوحدة الجذر، ولذلك سنضع ملف الوحدة <code>hosting</code> في مسار جديد يُسمّى بحسب آباء الوحدة في شجرة الوحدة، وفي هذه الحالة سيكون المسار هو src/front_of_house/‎.
</p>

<p>
	لنقل الوحدة <code>hosting</code> نعدّل الملف src/front_of_house.rs بحيث يحتوي على تصريح الوحدة <code>hosting</code> فقط:
</p>

<p>
	اسم الملف: src/front_of_house.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4355_49" style=""><span class="pln">pub mod hosting</span><span class="pun">;</span></pre>

<p>
	نُنشئ بعد ذلك مسار src/front_of_house وملف hosting.rs ليحتوي على التعريف الخاص بالوحدة <code>hosting</code>:
</p>

<p>
	اسم الملف: src/front_of_house/hosting.rs
</p>

<pre class="ipsCode">pub fn add_to_waitlist() {}
</pre>

<p>
	إذا وضعنا hosting.rs في المجلد src بدلًا من المجلد الحالي فإن المصرّف سيتوقع رؤية شيفرة hosting.rs في الوحدة <code>hosting</code> المصرح عنها في جذر الوحدة المُصرّفة وليس المصرح عنها وحدة ابن للوحدة <code>front_of_house</code>. تُملي قواعد المصرف بخصوص مسارات الملفات والوحدات أهمية تنظيمها بالنسبة لشجرة الوحدة الخاصة بالمشروع.
</p>

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

<p>
	لاحظ أن تعليمة <code>pub use crate::front_of_house::hosting</code> الموجودة في src/lib.rs لم تتغير، إذ لا تؤثّر <code>use</code> على الملفات التي ستُصرَّف مثل جزء من الوحدة المُصرّفة. تعرّف الكلمة المفتاحية <code>mod</code> الوحدات، إلا أن رست تنظر إلى الملف الذي يحمل الاسم ذاته الخاص بالوحدة للبحث عن الشيفرة البرمجية الخاصة بتلك الوحدة.
</p>

<h3>
	مسارات ملفات مختلفة
</h3>

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

<ul>
	<li>
		المسار src/front_of_house.rs (وهو مسار تكلمنا عنه سابقًا).
	</li>
	<li>
		المسار src/front_of_house/mod.rs (مسار قديم إلا أنه مدعوم).
	</li>
</ul>

<p>
	سينظر المصرف بالنسبة لوحدة جزئية من <code>front_of_house</code> تدعى <code>hosting</code> إلى اللشيفرة البرمجية الخاصة بالوحدة في:
</p>

<ul>
	<li>
		المسار src/front_of_house/hosting.rs (مسار ناقشناه سابقًا).
	</li>
	<li>
		المسار src/front_of_house/hosting/mod.rs (مسار قديم إلا أنه مدعوم).
	</li>
</ul>

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

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

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html/" rel="external nofollow">Managing Growing Projects with Packages, Crates, and Modules</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D9%84%D8%A7%D8%A6%D8%AD%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D9%82%D9%8A%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D8%B9%D8%A9-vectors-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1875/" rel="">تخزين لائحة من القيم باستخدام الأشعة Vectors في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%B4%D8%AC%D8%B1%D8%A9-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A9-module-tree-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1873/" rel="">المسارات paths وشجرة الوحدة module tree في رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B5%D8%B1%D9%81%D8%A9-crates-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1853/" rel="">الحزم packages والوحدات المصرفة crates في لغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1874</guid><pubDate>Wed, 08 Feb 2023 16:09:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x633;&#x627;&#x631;&#x627;&#x62A; paths &#x648;&#x634;&#x62C;&#x631;&#x629; &#x627;&#x644;&#x648;&#x62D;&#x62F;&#x629; module tree &#x641;&#x64A; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%B4%D8%AC%D8%B1%D8%A9-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A9-module-tree-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1873/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/407389647_-paths---module-tree---Rust.png.6d7d4a894f147cdc74c72d3fc67478ae.png" /></p>
<p>
	يُستخدم المسار path بنفس الطريقة المُستخدمة عند التنقل ضمن نظام الملفات في الحاسوب حتى ندلّ رست على مكان وجود عنصر ما ضمن شجرة الوحدة module tree، وبالتالي علينا معرفة مسار الدالة أولًا إذا أردنا استدعائها.
</p>

<p>
	قد يكون المسار واحدًا من النوعين التاليين:
</p>

<ul>
	<li>
		المسار المُطلق absolute path: وهو المسار الكامل بدءًا من جذر الوحدة المصرّفة؛ إذ أن المسار المُطلق لشيفرة برمجية موجودة في وحدة مصرّفة خارجية تبدأ باسم الوحدة المصرّفة بينما يبدأ مسار شيفرة برمجية داخل الوحدة المصرّفة الحالية المُستخدمة بالكلمة <code>crate</code>.
	</li>
	<li>
		المسار النسبي relative path: ويبدأ هذا المسار من الوحدة المصرّفة الحالية المُستخدمة ويستخدم الكلمة المفتاحية <code>self</code>، أو <code>super</code>، أو معرّف ينتمي إلى الوحدة نفسها.
	</li>
</ul>

<p>
	يُتبع كلا نوعَي المسارات السابقَين بمعرّف identifier واحد، أو أكثر ويفصل بينهما نقطتان مزدوجتان <code>::</code>.
</p>

<p>
	بالعودة إلى الشيفرة 1 في <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B5%D8%B1%D9%81%D8%A9-crates-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1853/" rel="">المقالة السابقة</a>، لنفترض أننا نريد استدعاء الدالة <code>add_to_waitlist</code>، وهذا يقتضي أن نسأل أنفسنا: ما هو مسار الدالة <code>add_to_waitlist</code>؟ تحتوي الشيفرة 3 على الشيفرة 1 مع إزالة بعض الوحدات والدوال.
</p>

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

<p>
	تشكل الدالة <code>eat_at_restaurant</code> جزءًا من الواجهة البرمجية العامة public <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الخاصة بوحدة المكتبة المصرّفة library crate، لذا نُضيف الكلمة المفتاحية <code>pub</code> إليها، وسنناقش المزيد من التفاصيل بخصوص <code>pub</code> في الفقرة التالية.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_9" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    mod hosting </span><span class="pun">{</span><span class="pln">
        fn add_to_waitlist</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">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// مسار مطلق</span><span class="pln">
    crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">

    </span><span class="com">// مسار نسبي</span><span class="pln">
    front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3: استدعاء الدالة add<em>to</em>waitlist باستخدام المسار المُطلق والمسار النسبي]
</p>

<p>
	نستخدم مسارًا مُطلقًا عندما نريد استدعاء الدالة <code>add_to_waitlist</code> داخل <code>eat_at_restaurant</code> للمرة الأولى، ويمكننا استخدام المسار المطلق بدءًا بالكلمة المفتاحية <code>crate</code> بالنظر إلى أن الدالة <code>add_to_waitlist</code> معرفة في نفس الوحدة المصرّفة الخاصة بالدالة <code>eat_at_restaurant</code>، ومن ثمّ نضمّن كل من الوحدات الأخرى الموجودة في شجرة الوحدة module tree حتى الوصول إلى الدالة <code>add_to_waitlist</code>. يمكنك تخيّل هذا الأمر بصورةٍ مشابهة لنظام الملفات على حاسوبك، إذ نكتب المسار <code>‎/front_of_house/hosting/add_to_waitlist</code> لتشغيل البرنامج <code>add_to_waitlist</code>، إلا أننا نستخدم الكلمة المفتاحية <code>crate</code> للدلالة على جذر الوحدة المصرّفة بدلًا من استخدام <code>/</code> في بداية المسار، وهو أمرٌ مشابه لكتابة <code>/</code> في <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> حتى تصل إلى جذر نظام الملفات على حاسوبك.
</p>

<p>
	نستخدم المسار النسبي في المرة الثانية التي نستدعي <code>add_to_waitlist</code> في <code>eat_at_restaurant</code>، ويبدأ المسار هنا بالاسم <code>front_of_house</code>، وهو اسم الوحدة المعرفة ضمن نفس مستوى <code>eat_at_restaurant</code> في شجرة الوحدة، وسيستخدم نظام الملفات المكافئ المسار <code>front_of_house/hosting/add_to_waitlist</code> بدءًا باسم الوحدة مما يعني أن المسار هو مسار نسبي.
</p>

<p>
	يجب الاختيار بين المسار المطلق والنسبي بناءً على مشروعك ويعتمد على إذا ما كنت ستميل غالبًا إلى نقل شيفرة تعريف العنصر البرمجية وتفريقها عن الشيفرة البرمجية التي تستخدم ذلك العنصر، أو إذا كنت ستبقيهما سويًا. على سبيل المثال، إذا أردنا نقل الوحدة <code>front_of_house</code> والدالة <code>eat_at_restaurant</code> إلى وحدة باسم <code>customer_experience</code>، سنضطر إلى تحديث المسار المطلق الخاص بالدالة <code>add_to_waitlist</code>، إلا أن المسار سيبقى صالحًا في حال استخدمنا المسار النسبي، لكن إذا نقلنا الدالة <code>eat_at_restaurant</code> بصورةٍ منفصلة إلى وحدة جديدة تدعى <code>dining</code> فلن يكون المسار النسبي لاستدعاء الدالة <code>add_to_waitlist</code> صالحًا بعد الآن ويجب تحديثه، إلا أن المسار المطلق سيبقى صالحًا. نفضّل هنا المسارات المطلقة، لأننا على الأغلب سنحرّك تعريف الشيفرة البرمجية واستدعاء العناصر على نحوٍ متفرق عن بعضهما بعضًا.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_12" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> restaurant v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/restaurant)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0603</span><span class="pun">]:</span><span class="pln"> module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln"> is </span><span class="kwd">private</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">9</span><span class="pun">:</span><span class="lit">28</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">9</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                            </span><span class="pun">^^^^^^^</span><span class="pln"> </span><span class="kwd">private</span><span class="pln"> module
  </span><span class="pun">|</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> the module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln"> is defined here
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     mod hosting </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">     </span><span class="pun">^^^^^^^^^^^</span><span class="pln">

error</span><span class="pun">[</span><span class="pln">E0603</span><span class="pun">]:</span><span class="pln"> module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln"> is </span><span class="kwd">private</span><span class="pln">
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">12</span><span class="pun">:</span><span class="lit">21</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">12</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">                     </span><span class="pun">^^^^^^^</span><span class="pln"> </span><span class="kwd">private</span><span class="pln"> module
   </span><span class="pun">|</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> the module </span><span class="pun">`</span><span class="pln">hosting</span><span class="pun">`</span><span class="pln"> is defined here
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">     mod hosting </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="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0603</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">restaurant</span><span class="pun">`</span><span class="pln"> due to </span><span class="lit">2</span><span class="pln"> previous errors</span></pre>

<p style="text-align: center;">
	[الشيفرة 4: أخطاء المصرف الناجمة عن تصريف الشيفرة 3]
</p>

<p>
	تدلنا رسالة الخطأ على أن الوحدة <code>hosting</code> هي وحدة خاصة، بمعنى أنه على الرغم من استخدامنا للمسار الصحيح الخاص بوحدة <code>hosting</code> ودالة <code>add_to_waitlist</code> إلا أن <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> لن تسمح لنا باستخدامهما لأنه لا يوجد لدينا سماحية الوصول إلى هذه الأجزاء الخاصة. جميع العناصر في رست (دوال وتوابع وهياكل و<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/" rel="">تعدادات</a> ووحدات وثوابت) هي خاصة بالوحدة الأب (الأصل) فقط افتراضيًا، وإذا أردت جعل عنصر ما مثل دالة أو هيكل خاصًا، فعليك وضعه داخل الوحدة.
</p>

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

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

<h2>
	كشف المسارات باستخدام الكلمة المفتاحية pub
</h2>

<p>
	بالعودة إلى الخطأ الموجود في الشيفرة 4 الذي كان مفاده أن الوحدة <code>hosting</code> هي وحدة خاصة، نريد أن تمتلك الدالة <code>eat_at_restaurant</code> الموجودة في الوحدة الأب وصولًا إلى الدالة <code>add_to_waitlist</code> الموجودة في الوحدة الابن، ولتحقيق ذلك نُضيف الكلمة المفتاحية <code>pub</code> إلى الوحدة <code>hosting</code> كما هو موضح في الشيفرة 5.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_15" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        fn add_to_waitlist</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">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// مسار مطلق</span><span class="pln">
    crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">

    </span><span class="com">// مسار نسبي</span><span class="pln">
    front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 5: التصريح عن الوحدة hosting باستخدام الكلمة المفتاحية pub لاستخدامها داخل eat<em>at</em>restaurant]
</p>

<p>
	لسوء الحظ، تتسبب الشيفرة 5 بخطأ موضح في الشيفرة 6.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_17" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> restaurant v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/restaurant)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0603</span><span class="pun">]:</span><span class="pln"> function </span><span class="pun">`</span><span class="pln">add_to_waitlist</span><span class="pun">`</span><span class="pln"> is </span><span class="kwd">private</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">9</span><span class="pun">:</span><span class="lit">37</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">9</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">^^^^^^^^^^^^^^^</span><span class="pln"> </span><span class="kwd">private</span><span class="pln"> function
  </span><span class="pun">|</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> the function </span><span class="pun">`</span><span class="pln">add_to_waitlist</span><span class="pun">`</span><span class="pln"> is defined here
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">9</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">         fn add_to_waitlist</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">

error</span><span class="pun">[</span><span class="pln">E0603</span><span class="pun">]:</span><span class="pln"> function </span><span class="pun">`</span><span class="pln">add_to_waitlist</span><span class="pun">`</span><span class="pln"> is </span><span class="kwd">private</span><span class="pln">
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">12</span><span class="pun">:</span><span class="lit">30</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">12</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">                              </span><span class="pun">^^^^^^^^^^^^^^^</span><span class="pln"> </span><span class="kwd">private</span><span class="pln"> function
   </span><span class="pun">|</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> the function </span><span class="pun">`</span><span class="pln">add_to_waitlist</span><span class="pun">`</span><span class="pln"> is defined here
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">9</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">         fn add_to_waitlist</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="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0603</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">restaurant</span><span class="pun">`</span><span class="pln"> due to </span><span class="lit">2</span><span class="pln"> previous errors</span></pre>

<p style="text-align: center;">
	[شيفرة 6: أخطاء المصرّف الناتجة عن بناء الشيفرة 5]
</p>

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

<p>
	تدلنا الأخطاء الموجودة في الشيفرة 6 إلى أن الدالة <code>add_to_waitlist</code> هي دالة خاصة، وتُطبَّق قوانين الخصوصية على الهياكل والتعدادات و<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">التوابع</a> و<a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">الدوال</a> كما هو الحال مع الوحدات.
</p>

<p>
	دعنا نجعل من الدالة <code>add_to_waitlist</code> دالة عامة بإضافة الكلمة المفتاحية <code>pub</code> قبل تعريفها كما هو موضح في الشيفرة 7.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_21" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    pub mod hosting </span><span class="pun">{</span><span class="pln">
        pub fn add_to_waitlist</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">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// مسار مطلق</span><span class="pln">
    crate</span><span class="pun">::</span><span class="pln">front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">

    </span><span class="com">// مسار نسبي</span><span class="pln">
    front_of_house</span><span class="pun">::</span><span class="pln">hosting</span><span class="pun">::</span><span class="pln">add_to_waitlist</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 7: إضافة الكلمة المفتاحية pub إلى mod hosting و fn add<em>to</em>waitlist مما يسمح لنا باستدعاء الدالة من eat<em>at</em>restaurant]
</p>

<p>
	يمكننا الآن تصريف الشيفرة البرمجية بنجاح. دعنا ننظر إلى المسارات المطلقة والمسارات النسبية حتى نفهم لماذا تسمح لنا إضافة <code>pub</code> باستخدام هذه المسارات في <code>add_to_waitlist</code> مع مراعاة قوانين الخصوصية.
</p>

<p>
	نبدأ بكتابة <code>crate</code> في المسار المطلق وهو جذر شجرة الوحدة الخاصة بالوحدة المصرّفة. تُعرّف الوحدة <code>front_of_house</code> في جذر الوحدة المصرّفة، إلا أنها ليست عامة، وذلك لأن الدالة <code>eat_at_restaurant</code> معرفة في الوحدة ذاتها الخاصة بالوحدة <code>front_of_house</code> (أي أن <code>eat_at_restaurant</code> و <code>front_of_house</code> أشقاء)، ويُمكننا الإشارة إلى <code>front_of_house</code> من <code>eat_at_restaurant</code>. تاليًا تبدو الوحدة <code>hosting</code> معلّمة marked بفضل الكلمة المفتاحية <code>pub</code>، إذ يمكننا الوصول إلى الوحدة الأب الخاصة بالوحدة <code>hosting</code>، وبالتالي يمكننا الوصول إلى <code>hosting</code>، وأخيرًا، الدالة <code>add_to_waitlist</code> مُعلّمة بالكلمة المفتاحية <code>pub</code>، وبالتالي يعمل بقية المسار ويُعد استدعاء الدالة هذا صالحًا.
</p>

<p>
	نعتمد في المسار النسبي نفس المنطق في المسار المطلق باستثناء الخطوة الأولى، إذ بدلًا من البدء بجذر الوحدة المصرّفة، يبدأ المسار من الوحدة <code>front_of_house</code>، التي تُعرّف في الوحدة ذاتها الخاصة بالوحدة <code>eat_at_restaurant</code>، وبالتالي يبدأ المسار النسبي من الوحدة التي يعمل عندها تعريف الوحدة <code>eat_at_restaurant</code>. تبدو الوحدة <code>hosting</code> و <code>add_to_waitlist</code> معلّمة بفضل الكلمة المفتاحية <code>pub</code>، ولذلك يعمل بقية المسار ويُعد استدعاء الدالة هذا صالحًا.
</p>

<p>
	إذا أردت مشاركة وحدة المكتبة المصرّفة الخاصة بك بحيث تستفيد مشاريع أخرى من الشيفرة البرمجية الخاصة بالوحدة المصرّفة، ستكون <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهتك البرمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> </a>العامة هي نقطة الوصل بين مستخدمي الوحدة المصرّفة ومحتوياتها وهي التي تحدد كيفية تفاعل المستخدمين مع شيفرتك البرمجية، وهناك الكثير من الأشياء التي يجب وضعها في الحسبان لإدارة التغييرات التي تجريها على الواجهة البرمجية العامة حتى تجعل عملية الاعتماد على وحدتك المصرّفة أسهل بالنسبة للمستخدمين، إلا أن هذه الأشياء خارج نطاق موضوعنا هنا، وإذا كنت مهتمًا بهذا الخصوص عليك رؤية <a href="https://rust-lang.github.io/api-guidelines/" rel="external nofollow">دليل رست الخاصة بالواجهات البرمجية</a>.
</p>

<h3>
	الممارسات المثلى للحزم التي تحتوي على وحدات ثنائية مصرفة ووحدات مكتبة مصرفة
</h3>

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

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

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

<h2>
	كتابة المسارات النسبية باستخدام super
</h2>

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

<p>
	ألقِ نظرةً إلى الشيفرة 8 التي تصف موقفًا معينًا، ألا وهو تصحيح الطاهي لطلب غير صحيح وإحضاره بنفسه شخصيًا إلى الزبون. تستدعي الدالة <code>fix_incorrect_order</code> المُعرفة في الوحدة <code>back_of_house</code> الدالة <code>deliver_order</code> المعرّفة في الوحدة الأب بتحديد المسار إلى الدالة <code>deliver_order</code> باستخدام الكلمة المفتاحية <code>super</code> في البداية:
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_24" style=""><span class="pln">fn deliver_order</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

mod back_of_house </span><span class="pun">{</span><span class="pln">
    fn fix_incorrect_order</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        cook_order</span><span class="pun">();</span><span class="pln">
        super</span><span class="pun">::</span><span class="pln">deliver_order</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fn cook_order</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 8: استدعاء دالة باستخدام المسار النسبي بدءًا بالكلمة super]
</p>

<p>
	تتواجد الدالة <code>fix_incorrect_order</code> في الوحدة <code>back_of_house</code>، لذا يمكننا استخدام <code>super</code> للإشارة إلى الوحدة الأب الخاصة بالوحدة <code>back_of_house</code> التي هي في هذه الحالة الوحدة <code>crate</code> الجذر، ومن هناك نبحث عن <code>deliver_order</code> ونجده بنجاح. نعتقد هنا أن الوحدة <code>back_of_house</code> والدالة <code>deliver_order</code> سيبقيان سويًا نظرًا للعلاقة فيما بينهما مهما تغيّر تنظيم شجرة الوحدة، وبالتالي استخدمنا <code>super</code> بحيث نختصر على أنفسنا أماكن تحديث الشيفرة البرمجية في المستقبل إذا قرّرنا نقل الشيفرة البرمجية إلى وحدة مختلفة.
</p>

<h2>
	جعل الهياكل والتعدادات عامة
</h2>

<p>
	يمكننا أيضًا استخدام الكلمة المفتاحية <code>pub</code> لتعيين <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">الهياكل structs</a> والتعدادات enums على أنها عامة، إلا أن هناك بعض التفاصيل الإضافية لاستخدام <code>pub</code> مع الهياكل والتعدادات؛ فإذا استخدمنا <code>pub</code> قبل تعريف الهيكل، فسيتسبب هذا بإنشاء هيكل عام إلا أن حقول هذا الهيكل ستظلّ خاصة، ويمكن جعل كل حقل عامًا أو لا اعتمادًا على أسس وشروط كل حالة بحد ذاتها. نُعرّف في الشيفرة 9 هيكلًا عامًا باسم <code>back_of_house::Breakfast</code> بحقل عام <code>toast</code> وحقل خاص <code>seasonal_fruit</code>، يُحاكي هذا الأمر عملية اختيار الزبون لنوع الخبز الذي يأتي مع الوجبة واختيار الطاهي لنوع الفاكهة الذي يأتي مصحوبًا مع الوجبة بناءً على المتاح في مخزون المطعم؛ ولأن الفاكهة المُتاحة تتغير سريعًا حسب المواسم فالزبون لا يستطيع اختيار الفاكهة أو حتى رؤية النوع الذي سيحصل عليه.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_27" style=""><span class="pln">mod back_of_house </span><span class="pun">{</span><span class="pln">
    pub </span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Breakfast</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        pub toast</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        seasonal_fruit</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    impl </span><span class="typ">Breakfast</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        pub fn summer</span><span class="pun">(</span><span class="pln">toast</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Breakfast</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Breakfast</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                toast</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="pln">toast</span><span class="pun">),</span><span class="pln">
                seasonal_fruit</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"peaches"</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">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">//  Rye طلب فطور في الصيف مع خبز محمص من النوع راي</span><span class="pln">
    let mut meal </span><span class="pun">=</span><span class="pln"> back_of_house</span><span class="pun">::</span><span class="typ">Breakfast</span><span class="pun">::</span><span class="pln">summer</span><span class="pun">(</span><span class="str">"Rye"</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// غيّرنا رأينا بخصوص الخبز الذي نريده</span><span class="pln">
    meal</span><span class="pun">.</span><span class="pln">toast </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"Wheat"</span><span class="pun">);</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"I'd like {} toast please"</span><span class="pun">,</span><span class="pln"> meal</span><span class="pun">.</span><span class="pln">toast</span><span class="pun">);</span><span class="pln">

    </span><span class="com">// لن يُصرَّف السطر التالي إذا أزلنا تعليقه لأنه من غير المسموح رؤية أو تعدي الفاكهة الموسمية التي تأتي مع الوجبة</span><span class="pln">
    </span><span class="com">// meal.seasonal_fruit = String::from("blueberries");</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 9: هيكل يحتوي على بعض الحقول العامة والخاصة]
</p>

<p>
	بما أن الحقل <code>toast</code> في الهيكل <code>back_of_house::Breakfast</code> هو حقل عام، فهذا يعني أننا نستطيع الكتابة إلى والقراءة من الحقل <code>toast</code> في <code>eat_at_restaurant</code> باستخدام النقطة. لاحظ أنه لا يمكننا استخدام الحقل <code>seasonal_fruit</code> في <code>eat_at_restaurant</code> وذلك لأن الحقل <code>seasonal_fruit</code> هو حقل خاص. حاول إزالة تعليق السطر البرمجي الذي يُعدّل من قيمة الحقل <code>seasonal_fruit</code> وستحصل على خطأ.
</p>

<p>
	لاحظ أن الهيكل <code>back_of_house::Breakfast</code> بحاجة لتوفير دالة عامة مرتبطة به تُنشئ نسخةً من <code>Breakast</code> (سميناها <code>summer</code> في هذا المثال)، لأنه يحتوي على حقل خاص، ولن يصبح بالإمكان إنشاء نسخة من الهيكل <code>Breakfast</code> في <code>eat_at_restaurant</code> إذا لم يحتوي على دالة مشابهة، وذلك لأنه لن يكون بإمكاننا ضبط قيمة للحقل الخاص <code>seasonal_fruit</code> في <code>eat_at_restaurant</code>.
</p>

<p>
	وفي المقابل، إذا أنشأنا تعدادًا عامًا، ستكون جميع متغايراته variants عامة، ونحن بحاجة لاستخدام الكلمة المفتاحية <code>pub</code> مرةً واحدةً فقط قبل الكلمة <code>enum</code> كما هو موضح في الشيفرة 10.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4864_29" style=""><span class="pln">mod back_of_house </span><span class="pun">{</span><span class="pln">
    pub </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Appetizer</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Soup</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Salad</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

pub fn eat_at_restaurant</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let order1 </span><span class="pun">=</span><span class="pln"> back_of_house</span><span class="pun">::</span><span class="typ">Appetizer</span><span class="pun">::</span><span class="typ">Soup</span><span class="pun">;</span><span class="pln">
    let order2 </span><span class="pun">=</span><span class="pln"> back_of_house</span><span class="pun">::</span><span class="typ">Appetizer</span><span class="pun">::</span><span class="typ">Salad</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 10: تحديد المعدد على أنه عام يجعل جميع متغايراته عامة]
</p>

<p>
	يمكننا استخدام المتغايرات <code>Soup</code> و <code>Salad</code> في <code>eat_at_restaurant</code> وذلك لأننا أنشأنا التعداد <code>Appetier</code> على أنه تعداد عام.
</p>

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

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

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html/" rel="external nofollow">Managing Growing Projects with Packages, Crates, and Modules</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5-%D8%A8%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1874/" rel="">المسارات paths والنطاق الخاص بها في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B5%D8%B1%D9%81%D8%A9-crates-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1853/" rel="">الحزم packages والوحدات المصرفة crates في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel="">بنية match للتحكم بسير برامج لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية Ownership في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1873</guid><pubDate>Thu, 02 Feb 2023 16:01:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62D;&#x632;&#x645; packages &#x648;&#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x635;&#x631;&#x641;&#x629; crates &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A;</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B5%D8%B1%D9%81%D8%A9-crates-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1853/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/48644737_-packages--crates---Rust.png.8251cc3cf770cfc15cce8c725c9bc46e.png" /></p>
<p>
	سنُغطّي أولى أجزاء نظام الوحدة ألا وهو الحزم packages والوحدات المصرّفة crates.
</p>

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

<p>
	يُمكن أن تكون الوحدة المُصرَّفة ثنائية binary أو أن وحدة مكتبة مُصرَّفة library، وتُعد الوحدات المُصرَّفة الثنائية برامجًا يُمكنك تصريفها إلى ملف تنفيذي ومن ثم تشغيلها مثل برامج <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> command line programs أو <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="">الخوادم servers</a>، ويجب أن تحتوي الوحدات المُصرَّفة الثنائية على دالة تدعى <code>main</code> تُعرِّف ما الذي يحدث عند تشغيل الملف التنفيذي، وجميع الوحدات المُصرَّفة التي أنشأناها حتى اللحظة هي وحدات مصرّفة ثنائية.
</p>

<p>
	لا تحتوي الوحدات المكتبية المصرّفة على دالة <code>main</code> ولا تُصرَّف إلى ملف تنفيذي، وإنما تعرِّف وظائف بُنيَت بهدف الاستفادة منها من خلال مشاركتها من قبل عدّة مشاريع، ونذكر منها على سبيل المثال وحدة المكتبة المصرفة <code>rand</code> المُستخدمة في مقال <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">لُعبة تخمين الأرقام</a> السابق، والتي تقدّم خاصية توليد الأرقام العشوائية. عندما يذكر مستخدمو رست مصطلح وحدة مصرّفة، فهم يقصدون وحدة المكتبة المصرّفة، ويعتمدون مفهوم الوحدة المصرّفة على نحو تبادلي لمصطلح "المكتبة" السائد في <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">مفهوم البرمجة</a> العام.
</p>

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

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

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

<p>
	دعنا ننظر ما الذي يحدث عندما نُنشئ حزمة. نُدخل أوّلًا الأمر <code>cargo new</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_9" style=""><span class="pln">$ cargo </span><span class="kwd">new</span><span class="pln"> my</span><span class="pun">-</span><span class="pln">project
     </span><span class="typ">Created</span><span class="pln"> binary </span><span class="pun">(</span><span class="pln">application</span><span class="pun">)</span><span class="pln"> </span><span class="pun">`</span><span class="pln">my</span><span class="pun">-</span><span class="pln">project</span><span class="pun">`</span><span class="pln"> package
$ ls my</span><span class="pun">-</span><span class="pln">project
</span><span class="typ">Cargo</span><span class="pun">.</span><span class="pln">toml
src
$ ls my</span><span class="pun">-</span><span class="pln">project</span><span class="pun">/</span><span class="pln">src
main</span><span class="pun">.</span><span class="pln">rs</span></pre>

<p>
	بعد تنفيذ الأمر السابق، نستخدم الأمر <code>ls</code> لنرى ماذا أنشأ كارجو، إذ سنجد ضمن مجلد المشروع ملفًا اسمه Cargo.toml، والذي يمنحنا حزمة، ونجد أيضًا مجلد "src" يحتوي على الملف "main.rs". وإذا نظرنا إلى Cargo.toml فلن نجد هناك أي ذكر للملف src/main.rs، وذلك لأن كارجو يتبع اصطلاحًا معيّنًا بحيث يكون src/main.rs الوحدة الجذر للوحدة الثنائية المصرّفة باستخدام نفس اسم الحزمة. يعلم كارجو أيضًا أنه إذا احتوى مجلد الحزمة على src/lib.rs فهذا يعني أن الحزمة تحتوي على وحدة مكتبة مصرّفة باسم الحزمة ذاته و src/lib.rs هي الوحدة الجذر في هذه الحالة. يُمرّر كارجو ملفات الوحدة الجذر المصرّفة إلى <code>rustc</code> لبناء وحدة مكتبة مصرّفة أو وحدة ثنائية مصرّفة.
</p>

<p>
	لدينا هنا في هذه الحالة حزمة تحتوي src/main.rs فقط، وهذا يعني أنها تحتوي وحدة ثنائية مُصرّفة تُدعى <code>my-project</code>، وفي حالة احتواء المشروع على src/main.rs و src/lib.rs في ذات الوقت فهذا يعني أنه يحتوي على وحدتين مصرفتين، وحدة مكتبة مصرّفة ووحدة ثنائية مُصرّفة ويحتوي كلاهما على الاسم ذاته الخاص بالحزمة، ويمكن أن تحتوي الحزمة عدّة وحدات ثنائية مُصرّفة من خلال وضع الملفات في المجلد src/bin، بحيث يُمثّل كل ملف داخل هذا المجلد وحدة ثنائية مُصرّفة منفصلة. .
</p>

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

<p>
	سننتقل في هذا القسم للتكلم عن الوحدات modules والأجزاء الأخرى من نظام الوحدة، والتي تُسمى <strong>المسارات paths</strong>، وهي تسمح لك بتسمية العناصر؛ وسنتطرق أيضًا إلى الكلمة المفتاحية <code>use</code> التي تُضيف مسارًا إلى النطاق؛ والكلمة المفتاحية <code>pub</code> التي تجعل من العناصر عامة public؛ كما سنناقش الكلمة المفتاحية <code>as</code> والحزم الخارجية وعامل <code>glob</code>.
</p>

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

<h3>
	ورقة مرجعية للوحدات
</h3>

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

<ul>
	<li>
		ابدأ من وحدة الجذر المصرّفة root crate: عند تصريف وحدة مصرّفة ما، ينظر المصرّف أولًا إلى ملف وحدة الجذر المُصرّفة (عادةً src/lib.rs لوحدة المكتبة المصرّفة و src/main.rs للوحدة الثنائية المصرّفة).
	</li>
	<li>
		<strong>التصريح عن الوحدات:</strong> يُمكنك التصريح في ملف وحدة الجذر المصرّفة عن وحدة جديدة باسم معيّن وليكن "garden" بكتابة السطر البرمجي <code>mod garden;‎</code>، وسيبحث عندها المصرّف عن الشيفرة البرمجية داخل الوحدة في هذه الأماكن:
		<ul>
			<li>
				ضمن السطر ذاته inline: أي ضمن السطر الخاص بالتعليمة <code>mod garden</code> ضمن الأقواس المعقوصة عوضًا عن الفاصلة المنقوطة.
			</li>
			<li>
				في الملف src/garden.rs.
			</li>
			<li>
				في الملف src/garden/mod.rs.
			</li>
		</ul>
	</li>
	<li>
		<strong>التصريح عن الوحدات الفرعية submodules:</strong> يُمكنك التصريح عن وحدات فرعية لأي ملف غير وحدة الجذر المصرّفة، إذ يمكنك مثلًا التصريح عن <code>mod vegtables</code> في الملف src/garden.rs، وسيبحث المصرّف عن شيفرة الوحدة الفرعية في المجلد المُسمى للوحدة الأصل في هذه الأماكن:
		<ul>
			<li>
				ضمن السطر ذاته inline: أي ضمن السطر الخاص بالتعليمة <code>mod vegetables</code> ضمن الأقواس المعقوصة عوضًا عن الفاصلة المنقوطة.
			</li>
			<li>
				في الملف src/garden/vegetables.rs.
			</li>
			<li>
				في الملف src/garden/vegetables/mod.rs.
			</li>
		</ul>
	</li>
	<li>
		<strong>المسارات التي ستُشفّر في الوحدات:</strong> بمجرد أن تصبح الوحدة جزءًا من الوحدة المصرّفة، يمكنك الرجوع إلى الشيفرة البرمجية الموجودة في تلك الوحدة من أي مكانٍ آخر في نفس الوحدة المصرّفة، طالما تسمح قواعد الخصوصية بذلك، وذلك باستخدام المسار الواصل إلى هذه الشيفرة. يمكنك مثلًا العثور على نوع <code>Asparagus</code> في وحدة الخضار عند المسار <code>crate::garden::vegetables::Asparagus</code>.
	</li>
	<li>
		<strong>الخاص private والعام public</strong>: الشيفرة البرمجية الموجودة داخل الوحدة هي خاصة بالنسبة للوحدة الأصل افتراضيًا، ولجعل الوحدة عامة يجب أن نصرح عنها باستخدام <code>pub mod</code> بدلًا من <code>mod</code>، ولجعل العناصر الموجودة داخل الوحدة العامة عامة أيضًا نستخدم <code>pub</code> قبل التصريح عنها.
	</li>
	<li>
		<strong>الكلمة <code>use</code> المفتاحية:</strong> تُنشئ الكلمة المفتاحية <code>use</code> داخل النطاق اختصارًا للعناصر لتجنب استخدام المسارات الطويلة، إذ يمكنك في أي نطاق اختصار المسار <code>crate::garden::vegetables::Asparagus</code> باستخدام <code>use</code> عن طريق كتابة <code>use crate::garden::vegetables::Asparagus;‎</code> ومن ثمّ يمكنك كتابة <code>Asparagus</code> مباشرةً ضمن النطاق دون الحاجة لكتابة كامل المسار.
	</li>
</ul>

<p>
	إليك وحدة ثنائية مصرّفة اسمها <code>backyard</code> توضح القوانين السابقة. نُسمّي مسار الوحدة المصرّفة أيضًا <code>backyard</code> ويحتوي ذلك المسار على هذه الملفات والمسارات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_11" style=""><span class="pln">backyard
</span><span class="pun">├──</span><span class="pln"> </span><span class="typ">Cargo</span><span class="pun">.</span><span class="pln">lock
</span><span class="pun">├──</span><span class="pln"> </span><span class="typ">Cargo</span><span class="pun">.</span><span class="pln">toml
</span><span class="pun">└──</span><span class="pln"> src
    </span><span class="pun">├──</span><span class="pln"> garden
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> vegetables</span><span class="pun">.</span><span class="pln">rs
    </span><span class="pun">├──</span><span class="pln"> garden</span><span class="pun">.</span><span class="pln">rs
    </span><span class="pun">└──</span><span class="pln"> main</span><span class="pun">.</span><span class="pln">rs</span></pre>

<p>
	في هذه الحالة، يحتوي ملف وحدة الجذر المصرّفة src/main.rs على التالي:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_13" style=""><span class="pln">use crate</span><span class="pun">::</span><span class="pln">garden</span><span class="pun">::</span><span class="pln">vegetables</span><span class="pun">::</span><span class="typ">Asparagus</span><span class="pun">;</span><span class="pln">

pub mod garden</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let plant </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Asparagus</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"I'm growing {:?}!"</span><span class="pun">,</span><span class="pln"> plant</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يعني السطر البرمجي <code>pub mod garden;‎</code> بأن المصرّف سيضمّ الشيفرة البرمجية التي سيجدها في src/garden.rs، وهي:
</p>

<p>
	اسم الملف: src/garden.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_17" style=""><span class="pln">pub mod vegetables</span><span class="pun">;</span></pre>

<p>
	ويعني السطر <code>pub mod vegetables;‎</code> بأنّ الشيفرة البرمجية الموجودة في الملف src/garden/vegetables.rs ستُتضمّن أيضًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_20" style=""><span class="com">#[derive(Debug)]</span><span class="pln">
pub </span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Asparagus</span><span class="pln"> </span><span class="pun">{}</span></pre>

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

<h3>
	‎تجميع الشيفرات البرمجية المرتبطة ببعضها في الوحدات
</h3>

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

<p>
	دعنا نكتب وحدة مكتبة مصرّفة تزوّدنا بخصائص مطعم مثلًا، وسنعرّف داخلها بصمات signatures <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">الدوال</a>، لكن سنترك محتوى كل منها فارغًا لنركّز على جانب تنظيم الشيفرة البرمجية بدلًا من التطبيق الفعلي لمطعم.
</p>

<p>
	يُشار في مجال المطاعم إلى بعض الأجزاء بكونها أجزاء على الواجهة الأمامية front of house بينما يُشار إلى أجزاء أخرى بأجزاء في الخلفية back of house؛ وأجزاء الواجهة الأمامية هي حيث يتواجد الزبائن، أي جانب حجز الزبائن للمقاعد وأخذ الطلبات والمدفوعات منهم وتحضير النادل للمشروبات؛ بينما أجزاء الواجهة هي حيث يتواجد الطهاة وتُطهى الأطباق وتُنظّف الصحون والأعمال الإدارية التي يجريها المدير.
</p>

<p>
	من أجل هيكلة الوحدة المصرّفة بطريقة مماثلة للمطعم، نلجأ لتنظيم الدوال في وحدات متداخلة. لننشئ مكتبةً جديدة ونسميها <code>restaurant</code> بتنفيذ الأمر <code>cargo new restaurant --lib</code>، ثمّ نكتب الشيفرة 1 داخل الملف src/lib.rs لتعريف بعض الوحدات وبصمات الدوال.
</p>

<p>
	اسم الملف: src/lib.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_23" style=""><span class="pln">mod front_of_house </span><span class="pun">{</span><span class="pln">
    mod hosting </span><span class="pun">{</span><span class="pln">
        fn add_to_waitlist</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

        fn seat_at_table</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    mod serving </span><span class="pun">{</span><span class="pln">
        fn take_order</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

        fn serve_order</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

        fn take_payment</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 style="text-align: center;">
	[الشيفرة 1: وحدة front<em>of</em>house تحتوي على وحدات أخرى، وتحتوي هذه الوحدات الأخرى بدورها على دوال]
</p>

<p>
	نعرّف الوحدة عن طريق البدء بكتابة الكلمة المفتاحية <code>mod</code> ومن ثم تحديد اسم الوحدة (في حالتنا هذه الاسم هو <code>front_of_house</code>) ونضيف بعد ذلك أقواص معقوصة حول متن الوحدة. يمكننا إنشاء وحدات أخرى داخل وحدة ما وهذه هي الحالة مع الوحدات <code>hosting</code> و <code>serving</code>، يمكن للوحدات أيضًا أن تحتوي داخلها على تعريفات لعناصر أخرى، مثل الهياكل structs والتعدادات enums والثوابت constants والسمات traits أو الدوال كما هو موجود في الشيفرة 1.
</p>

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

<p>
	ذكرنا سابقًا أن src/main.rs و src/lib.rs هي وحدات جذر مُصرَّفة، والسبب في تسميتهما بذلك هو أن محتويات أيّ منهما يشكّل وحدةً تدعى <code>crate</code> في جذر هيكل الوحدة الخاص بالوحدة المصرّفة وكما تُعرف أيضًا بشجرة الوحدة module tree.
</p>

<p>
	توضح الشيفرة 2 شجرة الوحدة الخاصة بهيكل الشيفرة 1.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7503_25" style=""><span class="pln">crate
 </span><span class="pun">└──</span><span class="pln"> front_of_house
     </span><span class="pun">├──</span><span class="pln"> hosting
     </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> add_to_waitlist
     </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> seat_at_table
     </span><span class="pun">└──</span><span class="pln"> serving
         </span><span class="pun">├──</span><span class="pln"> take_order
         </span><span class="pun">├──</span><span class="pln"> serve_order
         </span><span class="pun">└──</span><span class="pln"> take_payment</span></pre>

<p style="text-align: center;">
	[الشيفرة 2: شجرة الوحدة للشيفرة 1]
</p>

<p>
	توضح الشجرة بأن بعض الوحدات متداخلة مع وحدات أخرى (على سبيل المثال الوحدة <code>hosting</code> متداخلة مع <code>front_of_house</code>)، كما توضح الشجرة أيضًا أن بعض الوحدات أشقاء siblings لبعضها، بمعنى أنها معرفة داخل الوحدة ذاتها (<code>hosting</code> و <code>serving</code> معرفتان داخل <code>front_of_house</code>). لإبقاء تشبيه شجرة العائلة، إذا كانت الوحدة (أ) محتواة داخل الوحدة (ب) نقول بأن الوحدة (أ) هي ابن child للوحدة (ب) وأن الوحدة (ب) هي الأب parent للوحدة (أ). لاحظ أن كامل الشجرة محتواة داخل الوحدة الضمنية المسماة <code>crate</code>.
</p>

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

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html/" rel="external nofollow">Managing Growing Projects with Packages, Crates, and Modules</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-paths-%D9%88%D8%B4%D8%AC%D8%B1%D8%A9-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A9-module-tree-%D9%81%D9%8A-%D8%B1%D8%B3%D8%AA-rust-r1873/" rel="">المسارات paths وشجرة الوحدة module tree في رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel="">بنية match للتحكم بسير برامج لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">استخدام التوابع methods ضمن الهياكل structs في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%84%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%B1%D8%B3%D8%AA-rust-r1849/" rel="">استخدام الهياكل structs لتنظيم البيانات في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">المراجع References والاستعارة Borrowing والشرائح Slices في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1853</guid><pubDate>Wed, 25 Jan 2023 16:01:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x64A;&#x629; match &#x644;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x628;&#x633;&#x64A;&#x631; &#x628;&#x631;&#x627;&#x645;&#x62C; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1155986118_-match------Rust.png.fc0d2d20bae0f8607fc96c8939e8f842.png" /></p>
<p>
	لدى <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> بنية construct فعالة جدًا للتحكم بسير البرنامج وتدعى ببنية <code>match</code>، إذ تسمح لك هذه البنية بمقارنة قيمة مع مجموعة من الأنماط، ثم تنفيذ شيفرة برمجية بناءً على النمط الموافق لهذه القيمة، ويمكن أن يكون النمط مشكلًا من قيمًا مجرّدة literal values، أو أسماء متغيرات، أو محرف بدل wildcard، أو أي شيء آخر، وسنتكلم لاحقًا عن جميع الأنواع المختلفة من الأنماط وعمل كل منها. تأتي قوة البنية <code>match</code> من قابلية التعبير الواضح عن الأنماط ومن أن المتصرف يتحقق من أن جميع الحالات الممكنة قد جرى التعامل معها.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_8" style=""><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Coin</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Penny</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Nickel</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Dime</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Quarter</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn value_in_cents</span><span class="pun">(</span><span class="pln">coin</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Coin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u8 </span><span class="pun">{</span><span class="pln">
    match coin </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Penny</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Nickel</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Dime</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Quarter</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3: تعداد enum وتعبير match يحتوي على جميع متغايرات التعداد مثل أنماط]
</p>

<p>
	دعنا نشرح التعبير <code>match</code> بالتفصيل في الدالة <code>value_in_cents</code>؛ إذ يبدأ أولًا بكتابة الكلمة المفتاحية <code>match</code> متبوعة بتعبير وهو قيمة القطعة النقدية <code>coin</code> في هذه الحالة، ويبدو هذا الأمر مشابهًا لاستخدام تعابير <code>if</code> إلا أن هناك فارقًا كبيرًا؛ إذ يحتاج تعبير <code>if</code> أن يُعيد قيمة بوليانية boolean إلا أن التعبير هنا يمكن أن يُعيد قيمةً من أي نوع، فعلى سبيل المثال نحصل هنا على القيمة <code>coin</code> من نوع التعداد <code>Coin</code> الذي عرفناه في السطر الأول.
</p>

<p>
	ننتقل الآن إلى أذرع arms البنية <code>match</code>، إذ يكون للذراع جزءان: نمط وشيفرة برمجية. يحتوي الذراع الأول هنا على نمط من النوع <code>Coin::Penny</code> ومن ثم العامل <code>&lt;=</code> الذي يفصل ما بين النمط والشيفرة البرمجية الواجب تنفيذها، والشيفرة البرمجية في هذه الحالة هي فقط القيمة "1"، ومن ثم يُفصل كل ذراع من الذراع الذي يليه باستخدام الفاصلة.
</p>

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

<p>
	الشيفرة البرمجية المرتبطة بكل ذراع هي تعبير، ونتيجة ذلك التعبير في الذراع الموافقة للقيمة هي القيمة التي تُعاد من تعبير <code>match</code> الكامل.
</p>

<p>
	لا تُستخدم عادةً الأقواس المعقوصة curly brackets، إذا كانت الشيفرة البرمجية في الذراع قصيرة كما هو الحال في الشيفرة 3، إذ تُعيد الشيفرة قيمة واحدة فقط مباشرةً، إلا أنه يجب علينا استخدام الأقواس المعقوصة إذا أردنا تنفيذ عدة أسطر برمجية داخل ذراع البنية <code>match</code>، ويكون استخدام الفاصلة بعد الذراع عندئذٍ اختياريًا. على سبيل المثال، تطبع الشيفرة البرمجية في المثال التالي "Lucky penny!‎" كل مرة يُستدعى فيها التابع باستخدام القيمة <code>Coin::Penny</code> إلا أنها ما زالت تُعيد أيضًا القيمة "1" في نهاية الكتلة البرمجية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_11" style=""><span class="pln">fn value_in_cents</span><span class="pun">(</span><span class="pln">coin</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Coin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u8 </span><span class="pun">{</span><span class="pln">
    match coin </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Penny</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            println</span><span class="pun">!(</span><span class="str">"Lucky penny!"</span><span class="pun">);</span><span class="pln">
            </span><span class="lit">1</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Nickel</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Dime</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Quarter</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الأنماط المرتبطة مع القيم
</h2>

<p>
	لذراع البنية <code>match</code> ميزةٌ مفيدةٌ أخرى، وهي قدرة ربط أجزاء من القيمة لتوافق النمط، وهذه هي الطريقة المتبعة عندما نريد الحصول على قيم من متغايرات التعدادات. دعنا نعدل مثلًا متغايرات التعداد السابق بحيث نستطيع تخزين بعض البيانات داخله. سكّت الولايات المتحدة من العام 1999 إلى 2008 قطعًا نقدية بقيمة ربع دولار بتصاميم مختلفة لكلٍ من الولايات الخمسين على أحد الجوانب، ولا يوجد أي قطع نقدية أخرى تحتوي على تصاميم خاصة بالولايات. إذًا، نحتاج وضع القيمة الإضافية فقط في الأرباع، ويمكننا إضافة هذه المعلومة داخل التعداد <code>enum</code> بتغيير المتغاير <code>Quarter</code> بحيث يحتوي على القيمة <code>UsState</code> مخزنةً بداخله وتلك العملية موضحة في الشيفرة 4.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_13" style=""><span class="com">#[derive(Debug)] // حتى نستطيع معاينة الولاية لاحقًا</span><span class="pln">
</span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">UsState</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Alabama</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Alaska</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Coin</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Penny</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Nickel</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Dime</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Quarter</span><span class="pun">(</span><span class="typ">UsState</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4: تعداد Coin يحتوي فيه المتغاير Quarter على القيمة UsState]
</p>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_15" style=""><span class="pln">fn value_in_cents</span><span class="pun">(</span><span class="pln">coin</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Coin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u8 </span><span class="pun">{</span><span class="pln">
    match coin </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Penny</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Nickel</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Dime</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Quarter</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            println</span><span class="pun">!(</span><span class="str">"State quarter from {:?}!"</span><span class="pun">,</span><span class="pln"> state</span><span class="pun">);</span><span class="pln">
            </span><span class="lit">25</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>coin</code> القيمة <code>Coin::Quarter(UsState::Alaska)‎</code> إذا استدعينا <code>value_in_cents(Coin::Quarter(UsState::Alaska))‎</code> وعندما نقارن تلك القيمة مع كل من أذرع البنية <code>match</code> لن يُطابق أي منهم القيمة وسنصل إلى <code>Coin::Quarter(state)‎</code> وبحلول تلك النقطة سيكون ربط القيمة <code>state</code> مع النوع <code>UsState::Alaska</code> ومن ثم يمكننا استخدام ذلك الربط في تعبير <code>println!‎</code>، مما سيسمح لنا بالحصول على قيمة الولاية الداخلية من متغاير <code>Quarter</code> ضمن التعداد <code>Coin</code>.
</p>

<h2>
	المطابقة مع Option<t>‎</t>
</h2>

<p>
	أردنا سابقًا الحصول على القيمة <code>T</code> الداخلية من الحالة <code>Some</code> عند استخدام <code>Option&lt;T&gt;‎</code>، إلا أنه يمكننا أيضًا التعامل مع <code>Option&lt;T&gt;‎</code> باستخدام <code>match</code> كما فعلنا في معدد <code>Coin</code>؛ إذ سنقارن متغايرات <code>Option&lt;T&gt;‎</code> عوضًا عن مقارنة العملات، إلا أن طريقة عمل تعبير <code>match</code> ستبقى كما هي.
</p>

<p>
	دعنا نقول أننا نريد كتابة دالة تأخذ <code>Option&lt;i32&gt;‎</code> مثل وسيط وتُضيف إلى قيمته "1" إذا كان هناك قيمةٌ داخله، وإذا لم يحتوي الوسيط على قيمة يجب أن تُعيد الدالة القيمة <code>None</code> وألّا تُجري أي عمليات أخرى.
</p>

<p>
	الدالة سهلة الكتابة جدًا وذلك بفضل <code>match</code> وستبدو كما هو موضح في الشيفرة 5.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_17" style=""><span class="pln">    fn plus_one</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        match x </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">None</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">None</span><span class="pun">,</span><span class="pln">
            </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let five </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
    let six </span><span class="pun">=</span><span class="pln"> plus_one</span><span class="pun">(</span><span class="pln">five</span><span class="pun">);</span><span class="pln">
    let none </span><span class="pun">=</span><span class="pln"> plus_one</span><span class="pun">(</span><span class="typ">None</span><span class="pun">);</span></pre>

<p style="text-align: center;">
	[الشيفرة 5: دالة تستخدم تعبير match على المتغير Option<i32>‎]</i32>
</p>

<p>
	دعنا نفحص التنفيذ الأول للدالة <code>plus_one</code> بالتفصيل، إذ يأخذ المتغير <code>x</code> الموجود داخل دالة <code>plus_one</code> القيمة <code>Some(5)‎</code> عند الاستدعاء <code>plus_one(five)‎</code> ومن ثم نقارن تلك القيمة مع كل ذراع ضمن <code>match</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_19" style=""><span class="pln">            </span><span class="typ">None</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">None</span><span class="pun">,</span></pre>

<p>
	لا تُطابق القيمة <code>Some(5)‎</code> النمط الأول <code>None</code> التالي، لذا نستمر بمحاولة النمط الذي يليه.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_21" style=""><span class="pln">            </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span></pre>

<p>
	هل يُطابق <code>Some(5)‎</code> النمط <code>Some(i)‎</code>؟ نعم. لدينا المتغاير ذاته وترتبط <code>i</code> بالقيمة التي تحتويها <code>Some</code> وبالتالي يأخذ <code>i</code> القيمة 5. تُنفّذ الشيفرة البرمجية الموجودة في ذراع <code>match</code> الموافقة، وبالتالي نُضيف "1" إلى قيمة <code>i</code> ونُنشأ قيمة <code>Some</code> جديدة باستخدام الناتج "6" الإجمالي داخله.
</p>

<p>
	دعنا ننظر إلى الاستدعاء الثاني للدالة <code>plus_one</code> في الشيفرة 5، إذ يأخذ المتغير <code>x</code> القيمة <code>None</code>. ندخل البنية <code>match</code> ونُقارن مع الذراع الأول.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_23" style=""><span class="pln">            </span><span class="typ">None</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">None</span><span class="pun">,</span></pre>

<p>
	حصلنا على مطابقة. ليس هناك أي قيمة لنضيفها لذا يتوقف البرنامج ويُعيد القيمة <code>None</code> على يمين المعامل <code>&lt;=</code> ولا تحدث أي مقارنة أخرى لأننا حصلنا على مطابقة مع الذراع الأولى.
</p>

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

<h2>
	يجب أن تكون بنى match شاملة
</h2>

<p>
	هناك جانب آخر من البنية <code>match</code> لم نناقشه بعد. ألقِ نظرةً على الإصدار التالي من دالة <code>plus_one</code> الذي يحتوي على خطأ برمجي ولن يُصرّف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_26" style=""><span class="pln">    fn plus_one</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        match x </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_28" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> enums v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/enums)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0004</span><span class="pun">]:</span><span class="pln"> non</span><span class="pun">-</span><span class="pln">exhaustive patterns</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="typ">None</span><span class="pun">`</span><span class="pln"> not covered
   </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">15</span><span class="pln">
    </span><span class="pun">|</span><span class="pln">
</span><span class="lit">3</span><span class="pln">   </span><span class="pun">|</span><span class="pln">         match x </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">|</span><span class="pln">               </span><span class="pun">^</span><span class="pln"> pattern </span><span class="pun">`</span><span class="typ">None</span><span class="pun">`</span><span class="pln"> not covered
    </span><span class="pun">|</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pun">`</span><span class="pln"> defined here
    </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> the matched value is of type </span><span class="pun">`</span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pun">`</span><span class="pln">
help</span><span class="pun">:</span><span class="pln"> ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an </span><span class="kwd">explicit</span><span class="pln"> pattern as shown
    </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln">   </span><span class="pun">~</span><span class="pln">             </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">i </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">5</span><span class="pln">   </span><span class="pun">~</span><span class="pln">             </span><span class="typ">None</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> todo</span><span class="pun">!(),</span><span class="pln">
    </span><span class="pun">|</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0004</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">enums</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	تعلم رست أننا لم نغطي جميع الحالات الممكنة وحتى أنها تعرف الأنماط التي نسيناها؛ إذ أن الأنماط في لغة رست شاملة بحيث أنها يجب أن تشمل أي حالة ممكنة حتى تكون الشيفرة البرمجية صالحة، وبالأخص في حالة <code>Option&lt;T&gt;‎</code>، إذ تذكرنا رست بالتعامل مع حالة <code>None</code> صراحةً، وتحمينا من افتراض أننا حصلنا على قيمة بينما نحن نملك قيمة فارغة في الحقيقة مما يجعل الخطأ ذو مليارات الدولارات الذي ناقشناه لاحقًا مستحيل الحدوث.
</p>

<h2>
	التعامل مع جميع الأنماط والمحرف _ المؤقت
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_30" style=""><span class="pln">    let dice_roll </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pun">;</span><span class="pln">
    match dice_roll </span><span class="pun">{</span><span class="pln">
        </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> add_fancy_hat</span><span class="pun">(),</span><span class="pln">
        </span><span class="lit">7</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> remove_fancy_hat</span><span class="pun">(),</span><span class="pln">
        other </span><span class="pun">=&gt;</span><span class="pln"> move_player</span><span class="pun">(</span><span class="pln">other</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fn add_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    fn remove_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    fn move_player</span><span class="pun">(</span><span class="pln">num_spaces</span><span class="pun">:</span><span class="pln"> u8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{}</span></pre>

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

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

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

<p>
	دعنا نغيّر من قوانين اللعبة بحيث يجب عليك إعادة رمي النرد مجددًا إذا حصلت على نتيجة مغايرة عن 3 أو 7، ولا نحتاج هنا لاستخدام القيم صراحةً وكل ما علينا هو وضع المحرف المميز <code>_</code> بدلًا من اسم المتغيّر <code>other</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_32" style=""><span class="pln">    let dice_roll </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pun">;</span><span class="pln">
    match dice_roll </span><span class="pun">{</span><span class="pln">
        </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> add_fancy_hat</span><span class="pun">(),</span><span class="pln">
        </span><span class="lit">7</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> remove_fancy_hat</span><span class="pun">(),</span><span class="pln">
        _ </span><span class="pun">=&gt;</span><span class="pln"> reroll</span><span class="pun">(),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fn add_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    fn remove_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    fn reroll</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	تحقق الشيفرة البرمجية السابقة شرط بنية <code>match</code>، الذي ينص على وجوب شموليتها، إذ أننا نتجاهل جميع القيم الأخرى في الذراع الأخير مما يعني أننا لم ننسى أي احتمال.
</p>

<p>
	يمكننا استخدام قيمة الواحدة unit value (نوع الصف الفارغ empty tuple type الذي ذكرناه سابقًا) مع ذراع المحرف المميز <code>_</code>، إذا أردنا تغيير قوانين اللعبة مجددًا بحيث لا يحصل أي شيء عندما تحصل على قيمة مغايرة عن القيمة 3 أو 7 :
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_34" style=""><span class="pln">    let dice_roll </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pun">;</span><span class="pln">
    match dice_roll </span><span class="pun">{</span><span class="pln">
        </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> add_fancy_hat</span><span class="pun">(),</span><span class="pln">
        </span><span class="lit">7</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> remove_fancy_hat</span><span class="pun">(),</span><span class="pln">
        _ </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    fn add_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    fn remove_fancy_hat</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

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

<p>
	هناك المزيد من الأنماط التي سنغطيها لاحقًا، إلا أننا سنتحدث الآن عن <code>if let</code> التي قد تكون مفيدةً في حالات يكون فيها استخدام التعبير <code>match</code> يتطلب صياغةً طويلة.
</p>

<h2>
	التحكم بسير البرنامج باستخدام if let
</h2>

<p>
	تسمح لك <code>if let</code> بجمع كل من <code>if</code> و <code>let</code> بطريقة أكثر اختصارًا مقارنةً باستخدام الأنماط و <code>match</code> مع تجاهل القيم الأخرى التي لا تهمنا. ألقِ نظرةً على البرنامج الموجود في الشيفرة 6 الذي يُطابق قيمة <code>&lt;Option&lt;u8</code> في المتغير <code>config_max</code> بحثًا عن قيمة واحدة ألا وهي متغاير <code>Some</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_36" style=""><span class="pln">    let config_max </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="lit">3u8</span><span class="pun">);</span><span class="pln">
    match config_max </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">max</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"The maximum is configured to be {}"</span><span class="pun">,</span><span class="pln"> max</span><span class="pun">),</span><span class="pln">
        _ </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(),</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 6: بنية match تنفذ شيفرة برمجية فقط في حالة الحصول على القيمة Some]
</p>

<p>
	إذا كانت القيمة هي <code>Some</code>، نطبع القيمة داخل المتغاير <code>Some</code> من خلال ربطها مع المتغير <code>max</code> في النمط، إلا أننا لا نريد فعل أي شيء إذا حصلنا على القيمة <code>None</code> ولتحقيق شرط البنية <code>match</code> بكونها تشمل كل الاحتمالات نُضيف <code>() &lt;= _</code> بعد معالجة متغاير واحد، وهذا الأسلوب في الكتابة مزعج وهناك بديل أفضل.
</p>

<p>
	بدلًا مما سبق، نستطيع اختصار الكتابة عن طريق استخدام <code>if let</code>، وتوضح الشيفرة البرمجية التالية استخدامها، إذ تؤدي الغرض ذاته مقارنةً بالشيفرة السابقة الموجودة في الشيفرة 6 باستخدام <code>match</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_38" style=""><span class="pln">    let config_max </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="lit">3u8</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> let </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">max</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> config_max </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"The maximum is configured to be {}"</span><span class="pun">,</span><span class="pln"> max</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	نستخدم مع <code>if let</code> نمطًا وتعبيرًا مفصولَين بإشارة مساواة، ويعمل هذا بطريقة مماثلة للبنية <code>match</code>، إذ يُعطى التعبير إلى <code>match</code> ويمثّل النمط الذراع الأولى له، وفي هذه الحالة هو <code>Some(max)‎</code>، وبالتالي تُربط قيمة المتغير <code>max</code> إلى القيمة الموجودة داخل <code>Some</code>، ويمكننا بعد ذلك استخدام <code>max</code> داخل كتلة <code>if let</code> بطريقة مماثلة لاستخدامنا <code>max</code> في ذراع البنية <code>match</code> الموافقة، ولن تُنفَّذ كتلة <code>if let</code> إذا لم تطابق القيمة النمط الخاص بها.
</p>

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

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

<p>
	يمكننا تضمين <code>else</code> مع <code>if let</code>، إذ أن كتلة <code>else</code> مطابقة لحالة <code>_</code> في تعبير <code>match</code> المساوي لكل من <code>if let</code> و <code>else</code>. تذكّر مثال تعريف التعداد <code>Coin</code> في الشيفرة 4، إذ كان متغاير <code>Quarter</code> يحمل قيمةً من النوع <code>UsState</code>، ونستطيع استخدام تعبير <code>match</code> عندها إذا أردنا عدّ جميع الأرباع التي رأيناها بينما نُعلن عن ولاية كل من الأرباع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_40" style=""><span class="pln">    let mut count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    match coin </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Quarter</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"State quarter from {:?}!"</span><span class="pun">,</span><span class="pln"> state</span><span class="pun">),</span><span class="pln">
        _ </span><span class="pun">=&gt;</span><span class="pln"> count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	أو يمكننا استخدام تعبير <code>if let</code> و <code>else</code> بدلًا من ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6542_42" style=""><span class="pln">    let mut count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> let </span><span class="typ">Coin</span><span class="pun">::</span><span class="typ">Quarter</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> coin </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"State quarter from {:?}!"</span><span class="pun">,</span><span class="pln"> state</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	إذًا، إذا صادفت موقفًا احتاج فيه برنامجك إلى المنطق الخاص بالبنية <code>match</code>، وكانت كتابة البنية طويلة ورتيبة تذكّر وجود <code>if let</code> في مخزونك أيضًا.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch06-00-enums.html/" rel="external nofollow">Enums and Pattern Matching</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%88%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B5%D8%B1%D9%81%D8%A9-crates-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1853/" rel="">الحزم packages والوحدات المصرفة crates في لغة رست</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/" rel="">التعدادات enums في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية Ownership في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1852</guid><pubDate>Sat, 21 Jan 2023 16:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x62F;&#x627;&#x62F;&#x627;&#x62A; enums &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/9780511_-enum----Rust.png.1a2db8d35cc29df49988be9df178ce4e.png" /></p>
<p>
	سننظر في هذا المقال إلى التعدادات enumerations -أو اختصارًا enums- وهي تسمح لنا بتعريف نوع من خلال تعدّد متغيراته variants المحتملة. سنعرّف أولًا المعدّدات ونستخدمها حتى نعرف إمكانياتها وقدرتها على ترميز البيانات، ثم سنستعرض التعداد المهم المسمى <code>option</code>، والذي يدل على قيمة إذا كان يحتوي على شيء أو لا شيء، ومن ثمّ سننظر إلى مطابقة الأنماط pattern matching باستخدام التعبير <code>match</code> الذي يجعل من عملية تشغيل شيفرات برمجية مختلفة بحسب قيم التعداد المختلفة عملية سهلة، وأخيرًا سنتكلم عن الباني <code>if let</code> وهو طريقة ومصطلح مختصر آخر مُتاح لنا للتعامل مع التعدادات في برامجنا.
</p>

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

<p>
	التعدادات هي طريقة لتعريف أنواع بيانات مُخصصة بصورةٍ مختلفة عن الهياكل structs؛ إذ تمنحنا الهياكل طريقةً لتجميع الحقول والبيانات ذات الصلة معًا، فمثلًا يُعرّف المستطيل <code>Rectangle</code> من خلال طوله <code>height</code> وعرضه <code>width</code>؛ بينما تعطينا التعدادات الخيار للقول أن القيمة هي واحدة من القيم الممكنة، فقد نرغب مثلًا بالقول أن المستطيل هو أحد الخيارات من مجموعة أشكال متاحة تتضمن أيضًا الدائرة <code>Circle</code> والمثلث <code>Triangle</code>. يسمح لنا <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> بترميز هذه الاحتمالات على هيئة تعداد.
</p>

<p>
	دعنا ننظر إلى حالة قد تستخدم فيها التعدادات في شيفرتك البرمجية ولننظر إلى فائدتها والأشياء التي تميزها عن الهياكل؛ لنقل أن تطبيقنا سيتعامل مع عناوين <a href="https://academy.hsoub.com/devops/networking/%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-ip-r497/" rel="">بروتوكول الإنترنت IP address</a>. المعياران المُستخدمان حاليًا في عناوين بروتوكول الإنترنت هما الإصدار الرابع والإصدار السادس، لذلك نستطيع استخدام التعداد لجميع المتغيرات variants في الحالتين، وهذا هو السبب في تسمية التعدادات بهذا الاسم.
</p>

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

<p>
	يمكننا التعبير عن هذا المفهوم في شيفرتنا البرمجية عن طريق تعريف التعداد <code>IpAddrKind</code> وإضافة أنواع عناوين الإنترنت الممكنة ألا وهي <code>V6</code> و <code>V4</code> والتي هي متغيرات التعداد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_8" style=""><span class="kwd">enum</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    V4</span><span class="pun">,</span><span class="pln">
    V6</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أصبح لدينا الآن التعداد <code>IpAddrKind</code> وهو نوع بيانات مخصص يمكننا استخدامه في أي مكان ضمن شيفرتنا البرمجية.
</p>

<h2>
	قيم التعداد
</h2>

<p>
	يُمكننا إنشاء نسخةٍ من كلا المتغيرَين في التعداد <code>IpAddrKind</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_10" style=""><span class="pln">    let four </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V4</span><span class="pun">;</span><span class="pln">
    let six </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V6</span><span class="pun">;</span></pre>

<p>
	لاحظ أن فضاء أسماء متغيرات التعداد موجود ضمن المعرّف identifier، ويمكننا استخدام نقطتين مزدوجتين <code>::</code> لفصل كل من اسم المتغيّر والمعرف، وهذا الأمر مفيد لأن كلا القيمَتين <code>IpAddrKind::V4</code> و <code>IpAddrKind::V6</code> من نفس النوع وهو <code>IpAddrKind</code>. يمكننا بعد ذلك تعريف دالة تأخذ أي قيمة من النوع <code>IpAddrKind</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_12" style=""><span class="pln">fn route</span><span class="pun">(</span><span class="pln">ip_kind</span><span class="pun">:</span><span class="pln"> </span><span class="typ">IpAddrKind</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_6352_14" style=""><span class="pln">    route</span><span class="pun">(</span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V4</span><span class="pun">);</span><span class="pln">
    route</span><span class="pun">(</span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V6</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_19" style=""><span class="pln">    </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        V4</span><span class="pun">,</span><span class="pln">
        V6</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        kind</span><span class="pun">:</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pun">,</span><span class="pln">
        address</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let home </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        kind</span><span class="pun">:</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V4</span><span class="pun">,</span><span class="pln">
        address</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"127.0.0.1"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    let loopback </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        kind</span><span class="pun">:</span><span class="pln"> </span><span class="typ">IpAddrKind</span><span class="pun">::</span><span class="pln">V6</span><span class="pun">,</span><span class="pln">
        address</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"::1"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">};</span></pre>

<p style="text-align: center;">
	[الشيفرة 1: تخزين البيانات ومتغيّر النوع IpAddrKind باستخدام الهيكل struct]
</p>

<p>
	عرفنا هنا هيكلًا <code>IpAddr</code> يحتوي على حقلين أحدهما <code>kind</code> من النوع <code>IpAddrKind</code> (وهو التعداد الذي عرفناه سابقًا) وحقل <code>address</code> من النوع <code>String</code>، ثم أنشأنا نسختين من هذا الهيكل، وأول نسخة هي <code>home</code> وتحمل القيمة <code>IpAddrKind::V4</code> في الحقل <code>kind</code> والقيمة <code>127.0.0.1</code> في الحقل <code>address</code>، وثاني النسخ هي <code>loopback</code> وتحمل القيمة <code>IpAddrKind::V6</code> (المتغيّر الثاني من النوع <code>IpAddrKind</code>) في حقل <code>kind</code> ويحتوي على القيمة <code>‎::1</code> في حقل العنوان <code>address</code>، وبالتالي استخدمنا هنا هيكلًا لتجميع القيمتين <code>kind</code> و <code>address</code> مع بعضهما وربطنا المتغيّر مع القيمة.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_21" style=""><span class="pln">    </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        V4</span><span class="pun">(</span><span class="typ">String</span><span class="pun">),</span><span class="pln">
        V6</span><span class="pun">(</span><span class="typ">String</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let home </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pun">::</span><span class="pln">V4</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"127.0.0.1"</span><span class="pun">));</span><span class="pln">

    let loopback </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pun">::</span><span class="pln">V6</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"::1"</span><span class="pun">));</span></pre>

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

<p>
	هناك ميزةٌ أخرى لاستخدام التعدادات عوضًا عن الهياكل، ألا وهي أن كل متغيّر يحصل على نوع مختلف وكمية مختلفة من البيانات المرتبطة به، إذ سيحصل نوع الإصدار الرابع من عنوان الإنترنت على أربع مكونات عددية تحمل قيمة تنتمي إلى المجال من 0 إلى 255. إذا أردنا تخزين عناوين الإصدار الرابع <code>V4</code> بأربع قيم من النوع <code>u8</code> مع المحافظة على إمكانية تمثيل عناوين الإصدار السادس <code>V6</code> مثل قيمة واحدة من النوع <code>String</code>، وهذا لن يكون هذا ممكنًا باستخدام الهياكل. إليك كيف تسمح لنا التعدادات بفعل ذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_23" style=""><span class="pln">    </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        V4</span><span class="pun">(</span><span class="pln">u8</span><span class="pun">,</span><span class="pln"> u8</span><span class="pun">,</span><span class="pln"> u8</span><span class="pun">,</span><span class="pln"> u8</span><span class="pun">),</span><span class="pln">
        V6</span><span class="pun">(</span><span class="typ">String</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let home </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pun">::</span><span class="pln">V4</span><span class="pun">(</span><span class="lit">127</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">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">

    let loopback </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pun">::</span><span class="pln">V6</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"::1"</span><span class="pun">));</span></pre>

<p>
	استعرضنا عدة طرق في تعريف هياكل البيانات لتخزين الإصدار الرابع والسادس من عناوين بروتوكول الإنترنت، إلا أن تخزين عناوين الإنترنت في الحقيقة ممكن التخزين والترميز بسهولة عن طريق <a href="https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html" rel="external nofollow">تعريف ضمن المكتبة القياسية</a>. دعنا ننظر إلى كيفية تعريف المكتبة القياسية للنوع <code>IpAddr</code>، إذ تُعرّف المكتبة القياسية التعداد مع معدّداته بصورةٍ مماثلة لما فعلناه سابقًا إلا أنها تُضمّن عناوين الإنترنت داخل المتغيّرات ضمن هيكلين مختلفين مُعرّفَين على نحوٍ مختلف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_25" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Ipv4Addr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Ipv6Addr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">IpAddr</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    V4</span><span class="pun">(</span><span class="typ">Ipv4Addr</span><span class="pun">),</span><span class="pln">
    V6</span><span class="pun">(</span><span class="typ">Ipv6Addr</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}</span></pre>

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

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

<p>
	دعنا ننظر إلى مثال آخر على التعدادات في الشيفرة 2، إذ يحتوي هذا المثال على أنواع متعددة ضمن متغيّرات التعداد.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_27" style=""><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Message</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Quit</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Move</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln"> i32 </span><span class="pun">},</span><span class="pln">
    </span><span class="typ">Write</span><span class="pun">(</span><span class="typ">String</span><span class="pun">),</span><span class="pln">
    </span><span class="typ">ChangeColor</span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 2: تعداد Message يحتوي على متغيّرات، يخزّن كل منها عدد ونوع مختلف من أنواع القيم]
</p>

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

<ul>
	<li>
		المتغيّر <code>Quit</code>، الذي لا يحتوي على أي بيانات مرتبطة به إطلاقًا.
	</li>
	<li>
		المتغيّر <code>Move</code>، الذي يحتوي على حقول مُسمّاة بصورةٍ مشابهة للهياكل.
	</li>
	<li>
		المتغيّر <code>Write</code>، الذي يحتوي على نوع <code>String</code> وحيد.
	</li>
	<li>
		المتغيّر <code>ChangeColor</code>، الذي يحتوي على ثلاث قيم من النوع <code>i32</code>.
	</li>
</ul>

<p>
	عملية تعريف التعداد السابق في الشيفرة 2 هي عملية مشابهة لتعريف أنواع مختلفة من الهياكل، والفارق الوحيد هنا هو أن التعدادات لا تستخدم الكلمة المفتاحية <code>struct</code> وكل المتغيّرات هنا مجمعة مع بعضها بعضًا ضمن النوع <code>Message</code>. تُخزّن الهياكل التالية البيانات التي يحملها التعداد السابق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_29" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">QuitMessage</span><span class="pun">;</span><span class="pln"> </span><span class="com">// unit هيكل وحدة</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">MoveMessage</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln">
    y</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">WriteMessage</span><span class="pun">(</span><span class="typ">String</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هيكل صف</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">ChangeColorMessage</span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">);</span><span class="pln"> </span><span class="com">// هيكل صف</span></pre>

<p>
	إلا أننا لن نصبح قادرين على تعريف دالة تأخذ أي من أنواع الرسائل بسهولة إذا استخدمنا هياكل مختلفة لكلّ منها نوعها المختلف كما هو الحال في التعداد <code>Message</code> المعرف في الشيفرة 2 الذي يمثّل نوعًا واحدًا فقط.
</p>

<p>
	هناك تشابه آخر بين التعدادات والهياكل؛ إذ يمكننا تعريف توابع في التعدادات بطريقة مشابهة لما يحدث في الهياكل باستخدام <code>impl</code>. إليك تابعًا باسم <code>call</code> يمكننا تعريفه ضمن التعداد <code>Message</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_31" style=""><span class="pln">    impl </span><span class="typ">Message</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        fn call</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// يُعرّف محتوى التابع هنا</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    let m </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">::</span><span class="typ">Write</span><span class="pun">(</span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">));</span><span class="pln">
    m</span><span class="pun">.</span><span class="pln">call</span><span class="pun">();</span></pre>

<p>
	تُستخدم <code>self</code> في متن التابع للحصول على القيمة المُعادة من استدعاء التابع، وفي هذا المثال نُنشئ متغيرًا <code>m</code> يحمل القيمة <code>Message::Write(String::from("hello"))‎</code>، وهذا ما ستكون قيمة <code>self</code> عليه داخل التابع <code>call</code> عند تنفيذ السطر <code>m.call()‎</code>.
</p>

<p>
	دعنا ننظر إلى تعداد شائع مفيد آخر ضمن المكتبة القياسية ألا وهو <code>Option</code>.
</p>

<h2>
	التعداد Option وميزاته بما يخص القيم الفارغة
</h2>

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

<p>
	يُنظر إلى تصميم <a href="https://academy.hsoub.com/programming/general/%D8%A3%D9%81%D8%B6%D9%84-10-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%AA%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7-r1746/" rel="">لغات البرمجة</a> بسياق المزايا التي تتضمنها، إلا أن المزايا التي لن تُضمّن مهمةٌ أيضًا، إذ لا تحتوي رست على ميزة القيمة الفارغة null التي تمتلكها العديد من لغات البرمجة الأخرى؛ والقيمة الفارغة null تعني أنه لا يوجد أي قيمة هناك، وتكون المتغيرات في لغات البرمجة التي تحتوي على القيمة الفارغة في حالتين، إما حالة فارغة أو حالة غير فارغة not-null.
</p>

<p>
	صرّح توني هواري Tony Hoare -مخترع القيمة الفارغة- في عام 2009 في عرض تقديمي بعنوان "المراجع الفارغة: خطأ بقيمة مليار دولار Null Reference: The Billion Dollar Mistake" ما يلي:
</p>

<blockquote class="ipsQuote" data-gramm="false" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		أدعوها بخطئي الذي كلف مليار دولار. كنت في وقتها أصمم أول نظام للأنواع للمراجع في لغة كائنية التوجه، وكان هدفي التأكد من أن جميع استخدامات المراجع هي استخدامات آمنة بالكامل وذلك عن طريق فحص المصرف تلقائيًا، إلا أنني لم أستطع مقاومة إغراء إضافة مرجع فارغ null reference وذلك لأنه كان سهل التطبيق ببساطة. أدى ذلك فيما بعد إلى أخطاء وثغرات لا تُعد ولا تُحصى وتعطُّل للنظام، مما تسبب بخسائر بمليارات الدولار في الأربعين سنة المنصرمة.
	</p>
</blockquote>

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

<p>
	المشكلة ليست بالمفهوم وإنما بالحل المُطبّق، ولهذا السبب لا تحتوي رست على النوع فارغ null، وإنما تحتوي على تعداد يدل على مفهوم عدم وجود قيمة أو عدم صلاحيتها ألا وهو التعداد <code>Option&lt;T&gt;‎</code> المعرف في المكتبة القياسية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_34" style=""><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Option</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">None</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">Some</span><span class="pun">(</span><span class="pln">T</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	التعداد <code>Option&lt;T&gt;‎</code> مفيد جدًا حتى أنه مضمّن في مقدمة البرنامج وليس عليك أن تُضيفه إلى النطاق يدويًا، كما أن متغيّراته مضمّنة أيضًا ويمكنك استخدام <code>Some</code> و <code>None</code> مباشرةً دون البدء بالبادئة <code>Option::‎</code>، إلا أن التعداد <code>Option&lt;T&gt;‎</code> هو تعداد مثل أي تعداد آخر و <code>Some(T)‎</code> و <code>None</code> هي متغيّرات من النوع <code>Option&lt;T&gt;‎</code>.
</p>

<p>
	طريقة كتابة <code>&lt;T&gt;</code> هي ميزة من ميزات رست التي لم نتحدث عنها بعد، وهي معامل نوع مُعمّم generic type parameter وسنتكلم عن الأنواع المعممة لاحقًا، وكل ما عليك معرفته الآن هو أن <code>&lt;T&gt;</code> يعني أن متغيّر <code>Some</code> من التعداد <code>Option</code> يستطيع تخزين جزء من أي نوع من البيانات وأي نوع يُستخدم في مكان <code>T</code> يجعل من النوع <code>Option&lt;T&gt;‎</code> نوعًا مختلفًا. إليك بعض الأمثلة التي تستخدم قيم <code>Option</code> لتخزين عدة أنواع من البيانات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_36" style=""><span class="pln">   let some_number </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
    let some_char </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="str">'e'</span><span class="pun">);</span><span class="pln">

    let absent_number</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i32&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">None</span><span class="pun">;</span></pre>

<p>
	نوع <code>some_number</code> هو Option<i32><code>‎</code>، ونوع <code>some_string</code> هو <code>Option&lt;char&gt;‎</code> وهو نوع مختلف تمامًا عن سابقه، وتستطيع رست تحديد هذه الأنواع بسبب استخدامنا للقيمة داخل متغيّر <code>Some</code>، إلا أن رست تتطلب منا تحديد نوع <code>Option</code> الكلي بالنسبة للمتغير <code>absent_number</code> ولا يستطيع المصرّف تحديد النوع الخاص بالمتغير <code>Some</code> بنفسه عن طريق النظر إلى قيمة <code>None</code> فقط، وعلينا إخبار رست هنا أننا نقصد أن <code>absent_number</code> هو من النوع <code>Option&lt;i32&gt;‎</code>.</i32>
</p>

<p>
	نعلم أن هناك قيمة موجودة عندما يكون لدينا قيمة في <code>Some</code>، أما عندما يكون لدينا قيمة في <code>None</code> نعلم أن هذا الأمر مكافئ للقيمة الفارغة null أي أنه لا يوجد لدينا قيمة صالحة. إذًا، لمَ وجود <code>Option&lt;T&gt;‎</code> هو أفضل من وجود القيمة الفارغة؟
</p>

<p>
	لأن <code>Option&lt;T&gt;‎</code> و <code>T</code> (إذ يمكن أن تدل <code>T</code> على أي نوع) هي من أنواع مختلفة ولن يسمح لنا المصرف باستخدام القيمة <code>Option&lt;T&gt;‎</code> على أنها قيمة صالحة. على سبيل المثال، لن تُصرَّف الشيفرة البرمجية التالية لأننا نحاول إضافة النوع <code>i8</code> إلى نوع <code>Option&lt;i8&gt;‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_38" style=""><span class="pln">    let x</span><span class="pun">:</span><span class="pln"> i8 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
    let y</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i8&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Some</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">

    let sum </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6352_40" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> enums v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/enums)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0277</span><span class="pun">]:</span><span class="pln"> cannot add </span><span class="pun">`</span><span class="typ">Option</span><span class="str">&lt;i8&gt;</span><span class="pun">`</span><span class="pln"> to </span><span class="pun">`</span><span class="pln">i8</span><span class="pun">`</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">5</span><span class="pun">:</span><span class="lit">17</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">     let sum </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="pun">|</span><span class="pln">                 </span><span class="pun">^</span><span class="pln"> no implementation </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">`</span><span class="pln">i8 </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Option</span><span class="str">&lt;i8&gt;</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the trait </span><span class="pun">`</span><span class="typ">Add</span><span class="pun">&lt;</span><span class="typ">Option</span><span class="str">&lt;i8&gt;</span><span class="pun">&gt;`</span><span class="pln"> is not implemented </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">`</span><span class="pln">i8</span><span class="pun">`</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the following other types implement trait </span><span class="pun">`</span><span class="typ">Add</span><span class="pun">&lt;</span><span class="typ">Rhs</span><span class="pun">&gt;`:</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a f32 as </span><span class="typ">Add</span><span class="str">&lt;f32&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a f64 as </span><span class="typ">Add</span><span class="str">&lt;f64&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a i128 as </span><span class="typ">Add</span><span class="str">&lt;i128&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a i16 as </span><span class="typ">Add</span><span class="str">&lt;i16&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a i32 as </span><span class="typ">Add</span><span class="str">&lt;i32&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a i64 as </span><span class="typ">Add</span><span class="str">&lt;i64&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a i8 as </span><span class="typ">Add</span><span class="str">&lt;i8&gt;</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;&amp;</span><span class="str">'</span><span class="pln">a isize as </span><span class="typ">Add</span><span class="str">&lt;isize&gt;</span><span class="pun">&gt;</span><span class="pln">
          and </span><span class="lit">48</span><span class="pln"> others

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0277</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">enums</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	تعني رسالة الخطأ السابقة أن رست لا تعرف كيفية إضافة <code>i8</code> إلى <code>Option&lt;i8&gt;‎</code> لأنهما من نوعين مختلفين. يتأكد المصرف عندما نحصل على قيمة من نوع مشابه إلى النوع <code>i8</code> في رست من أنه لدينا قيمة صالحة، ويمكننا تجاوز عملية التحقق بأمان دون الحاجة للتحقق من قيمة فارغة قبل استخدام هذه القيمة، إلا أنه يجب علينا أخذ الحيطة فقط في حال كان لدينا <code>Option&lt;i8&gt;‎</code> (أو أي نوع من قيمة نتعامل معها) وذلك إذا كان النوع لا يحمل أي قيمة وسيتأكد المصرف حينها من تعاملنا مع هذه الحالة قبل استخدام القيمة.
</p>

<p>
	بكلمات أخرى، يجب عليك تحويل النوع <code>Option&lt;T&gt;‎</code> إلى <code>T</code> قبل تنفيذ عمليات النوع <code>T</code> على القيمة، ويساعدنا هذا عمومًا على تشخيص أحد أكثر المشاكل شيوعًا في القيم الفارغة ألا وهي افتراض أن قيمة ما ليست فارغة وهي في الحقيقة فارغة.
</p>

<p>
	سيجعلك التخلص من المشكلة السابقة أكثر ثقة بشيفرتك البرمجية، إذ يتوجب عليك تحويل القيمة إلى النوع <code>Option&lt;T&gt;‎</code> يدويًا إذا أردت الحصول على القيمة التي من الممكن أن تكون فارغة، وعليك التعامل مع حالة كون القيمة فارغة إذا استخدمت هذه الطريقة، وتستطيع الافتراض بأمان أن أي قيمة ليست من النوع <code>Option&lt;T&gt;‎</code> ليست بقيمة فارغة، وهذا تصميم مقصود في لغة رست للحدّ من انتشار القيمة الفارغة وزيادة أمان شيفرة <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست البرمجية</a>.
</p>

<p>
	كيف تُخرج القيمة <code>T</code> خارج متغيّر <code>Some</code> عندما يكون لديك قيمة من النوع <code>Option&lt;T&gt;‎</code> وتريد استخدام القيمة؟ لدى التعداد <code>Option&lt;T&gt;‎</code> العديد من التوابع المفيدة في حالات متعددة ويمكنك النظر إليها من <a href="https://doc.rust-lang.org/stable/std/option/enum.Option.html" rel="external nofollow">التوثيق</a>، وستكون معرفة هذه التوابع الخاصة بالنوع <code>Option&lt;T&gt;‎</code> مفيدةً جدًا في رحلتك مع رست.
</p>

<p>
	يجب عليك كتابة شيفرة برمجية تتعامل مع كل متغيّر إذا أردت استخدام القيمة الموجودة في <code>Option&lt;T&gt;‎</code>، إذ يجب على شيفرتك البرمجية أن تُنفّذ فقط في حال كان داخل <code>Option&lt;T&gt;‎</code> قيمةً ما، والسماح لهذه الشيفرة البرمجية باستخدام القيمة <code>T</code> الداخلية، كما ينبغي وجود شيفرة برمجية أخرى تُنفّذ في حال كان هناك قيمة <code>None</code> بحيث لا تستخدم هذه الشيفرة البرمجية القيمة <code>T</code>. يسمح لنا تعبير <code>match</code> الذي يمثل باني للتحكم بسير البرنامج باستخدام التعدادات بتنفيذ هذا الأمر تمامًا، إذ سينفذ شيفرةً برمجيةً مختلفةً بحسب المتغيّر الموجود داخل التعداد، ويمكن للشيفرة البرمجية حينها استخدام هذه البيانات داخل القيمة الموافقة.
</p>

<p>
	ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch06-00-enums.html/" rel="external nofollow">Enums and Pattern Matching</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D9%86%D9%8A%D8%A9-match-%D9%84%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1852/" rel="">بنية match للتحكم بسير برامج لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">استخدام التوابع methods ضمن الهياكل structs في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">المراجع References والاستعارة Borrowing والشرائح Slices في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1851</guid><pubDate>Tue, 17 Jan 2023 16:08:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; methods &#x636;&#x645;&#x646; &#x627;&#x644;&#x647;&#x64A;&#x627;&#x643;&#x644; structs &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1057219526_--methods---struct----Rust.png.c7549e8c8a9ddcd2fa062de8913860b5.png" /></p>
<p>
	التوابع methods مشابهة <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">للدوال functions</a>، إذ نُصرّح عنها باستخدام الكلمة المفتاحية <code>fn</code> متبوعةً باسم التابع، ويمكن للتوابع أن تمتلك عدّة معاملات وأن تُعيد قيمةً ما، ويحتوي التابع بداخله على جزء من شيفرة برمجية تعمل عند استدعاء التابع في مكان آخر، إلا أن التوابع -على عكس الدوال- تُعرّف داخل الهيكل (أو داخل المعدّد enum، أو كائن سمة trait object وهو ما سنتكلم عنه لاحقًا)، ويكون المعامل الأول دائمًا هو <code>self</code> الذي يمثّل نسخةً من الهيكل التي يُستدعى التابع منها.
</p>

<h2>
	تعريف التوابع
</h2>

<p>
	دعنا نُعدّل الدالة <code>area</code> -في المقال السابق- التي تأخذ نسخةً من الهيكل <code>Rectangle</code> معاملًا لها، ونُنشئ بدلًا من ذلك تابع <code>area</code> معرّف داخل الهيكل <code>Rectangle</code> كما هو موضح في الشيفرة 13.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_7" style=""><span class="com">#[derive(Debug)]</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn area</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">*</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">height
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="pln">
        </span><span class="str">"The area of the rectangle is {} square pixels."</span><span class="pun">,</span><span class="pln">
        rect1</span><span class="pun">.</span><span class="pln">area</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 13: تعريف التابع area داخل الهيكل Rectangle]
</p>

<p>
	نبدأ بكتابة كتلة تطبيق implementation‏ <code>impl</code> داخل الهيكل <code>Rectangle</code> حتى نستطيع تعريف الدالة داخل سياق الهيكل، وسيكون كل شيء ضمن هذه الكتلة مرتبطًا بالنوع <code>Rectangle</code>، من ثمّ ننقل الدالة <code>area</code> إلى داخل أقواس الكتلة <code>impl</code> ونعدّل المعامل الأول -وفي هذه الحالة هو المعامل الوحيد- ليصبح <code>self</code> في بصمة الدالة وأي مكان آخر ضمنها. ننتقل إلى الدالة <code>main</code> وعوضًا عن استدعاء الدالة <code>area</code> وتمرير <code>rect1</code> مثل وسيط، سنستخدم طريقة كتابة التابع لاستدعاء التابع <code>area</code> على نسخة الهيكل <code>Rectangle</code>، إذ تتلخّص الطريقة بإضافة نقطة (.) بعد نسخة الهيكل متبوعةً باسم التابع ومن ثم القوسين وبداخلهما أي وسطاء.
</p>

<p>
	نستخدم <code>‎&amp;self</code> في بصمة الدالة <code>area</code> عوضًا عن <code>rectangle: &amp;Rectangle</code>، وفي الحقيقة <code>‎&amp;self</code> هو اختصار إلى <code>self: &amp;Self</code>، ويمثّل <code>Self</code> داخل الكتلة <code>impl</code> اسمًا مستعارًا للنوع الذي يحتوي داخله الكتلة <code>impl</code>،وهي في هذه الحالة <code>Rectangle</code>. يجب على التوابع أن تحتوي على وسيط باسم <code>self</code> من النوع <code>Self</code> مثل مُعامل أوّل، إذ تسمح لك رست باختصار الاسم إلى <code>self</code> في المعامل الأول للتابع، لاحظ أنّنا ما زلنا بحاجة الرمز <code>&amp;</code> أمام الاسم المختصر <code>self</code> وذلك للإشارة إلى أن التابع يستعير نسخةً من النوع <code>Self</code> كما فعلنا سابقًا باستخدام <code>rectangle: &amp;Rectangle</code>. يمكن للتوابع أن تمتلك الاسم <code>self</code> أو أن تستعير <code>self</code> على نحوٍ غير قابل للتعديل -كما فعلنا هنا- أو أن تستعير <code>self</code> مع إمكانية تعديل كما هو الحال في أي مُعامل آخر.
</p>

<p>
	اخترنا <code>‎&amp;self</code> هنا مثل معامل للسبب ذاته الذي دفعنا لاستخدام <code>‎&amp;Rectangle</code> في إصدار البرنامج السابق، وهو أننا لا نريد أخذ الملكيّة بل نريد الاكتفاء فقط بقراءة البيانات الموجودة في الهيكل دون التعديل عليها. إذا أردنا تغيير النسخة التي استدعينا التابع عليها مثل جزء من وظيفة التابع، فيجب علينا استخدام <code>‎&amp;mut self</code> مثل معامل أوّل بدلًا من ذلك. من النادر أن تجد تابعًا يأخذ ملكية نسخة ما باستخدام <code>self</code> فقط في المعامل الأول وتُستخدم هذه الطريقة عادةً عندما يحوِّل التابع الوسيط <code>self</code> إلى شيء آخر وتريد أن تمنع مستدعي التابع من استخدام النسخة الأصل بعد عملية التحويل.
</p>

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

<p>
	لاحظ أنه يمكننا اختيار اسم التابع على نحوٍ مماثل لاسم حقول الهيكل، على سبيل المثال يمكننا تعريف تابع داخل الهيكل <code>Rectangle</code> باستخدام اسم الحقل <code>width</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_9" style=""><span class="pln">impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn width</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> rect1</span><span class="pun">.</span><span class="pln">width</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"The rectangle has a nonzero width; it is {}"</span><span class="pun">,</span><span class="pln"> rect1</span><span class="pun">.</span><span class="pln">width</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نختار هنا أن نجعل التابع <code>width</code> يُعيد القيمة <code>true</code> إذا كانت القيمة <code>width</code> في نسخة الهيكل أكبر من 0، وإلا فالقيمة <code>false</code> إذا كانت القيمة مساوية إلى الصفر، ويمكننا الاستفادة من الحقل داخل التابع الذي يحمل الاسم ذاته لأي هدف كان، ثم ننتقل إلى الدالة <code>main</code> ونستخدم التابع بالشكل <code>rect1.width</code> مع الأقواس حتى تعلم رست أننا نقصد التابع <code>width</code>، إذ ستعلم رست أننا نقصد الحقل <code>width</code>، إذا لم نستخدم الأقواس.
</p>

<p>
	قد نحتاج في بعض الأحيان عندما نُعطي التابع الاسم ذاته لحقل ما أن يُعيد التابع هذا القيمة الموجودة في الحقل ولا شيء آخر، وتُدعى التوابع من هذا النوع بالتوابع الجالبة getters ولا تُطبّقها رست تلقائيًا كما هو الحال في معظم اللغات الأخرى. تُعد التوابع الجالبة مفيدة لأنها تُمكّنك من جعل الحقل خاصًّا private وجعل التابع عامًا public في ذات الوقت مما يمكنك من الوصول إلى الحقل وقراءته فقط بمثابة جزء من <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> العامة للنوع، وسنناقش معنى خاص وعام وكيفية جعل الحقل أو التابع خاصًا أو عامًا لاحقًا.
</p>

<h3>
	أين العامل '&lt;-' ؟
</h3>

<p>
	لدى لغة سي C و <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>‎ معاملان مختلفان لاستدعاء التوابع، إذ يُمكنك استخدام <code>.</code> إذا أردت استدعاء التابع على الكائن مباشرةً، أو استخدام المعامل <code>&lt;-</code> إذا أردت استدعاء التابع على مؤشر يُشير إلى الكائن وتريد أن تحصل dereference على المؤشر عن الكائن أولًا؛ أي بكلمات أخرى، إذا كان <code>object</code> مؤشرًا فكتابة <code>object-&gt;something()‎</code> مشابهة إلى <code>‎(‎*object).something()‎</code>.
</p>

<p>
	لا يوجد في رست مُكافئ للمعامل <code>&lt;-</code>، بل لدى رست ميزة تُدعى بالمرجع لعنوان الذاكرة والتحصيل التلقائي automatic referencing and dereferencing بدلًا من ذلك، واستدعاء التوابع هو واحدة من الأجزاء في <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">لغة رست</a> التي تتبع هذا السلوك.
</p>

<p>
	إليك كيفية عمل هذه الميزة: عند استدعاء التابع باستخدام <code>object.something()‎</code> تُضيف رست <code>&amp;</code> أو <code>‎&amp;mut</code> أو <code>*</code> تلقائيًا حتى يُطابق <code>object</code> بصمة التابع، أي بكلمات أخرى، السطرين البرمجيين متماثلين، إلا أن السطر البرمجي الأول يبدو أكثر ترتيبًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_14" style=""><span class="pln">p1</span><span class="pun">.</span><span class="pln">distance</span><span class="pun">(&amp;</span><span class="pln">p2</span><span class="pun">);</span><span class="pln">
</span><span class="pun">(&amp;</span><span class="pln">p1</span><span class="pun">).</span><span class="pln">distance</span><span class="pun">(&amp;</span><span class="pln">p2</span><span class="pun">);</span></pre>

<p>
	يعمل سلوك المرجع لعنوان الذاكرة التلقائي لأن للتوابع مستقبل receiver واضح ألا وهو النوع <code>self</code>، وتستطيع رست باستخدام المستقبل الواضح واسم التابع أن تعرف دون شك إذا ما كان التابع يقرأ (<code>‎&amp;self</code>) أو يعدّل (<code>‎&amp;mut self</code>) أو يستهلك (<code>self</code>)، وتُعدّ حقيقة أن رست تجعل من الاستعارة مباشرة لمستقبل التابع من أهم أجزاء ميزة الملكية في رست.
</p>

<h2>
	التوابع التي تحتوي على عدة معاملات
</h2>

<p>
	دعنا نتدرب على استخدام التوابع بتطبيق تابع ثاني ضمن الهيكل <code>Rectangle</code>، ونريد في هذه المرة أن تأخذ نسخةٌ من الهيكل <code>Rectangle</code> نسخةً أخرى من الهيكل ذاته وأن تُعيد <code>true</code> إذا كانت النسخة الثانية تتسع كاملةً داخل النسخة الأولى (<code>self</code>) وإلا فيجب أن تُعيد <code>false</code>، وسنستطيع كتابة الشيفرة 14 بعد تعريف التابع <code>can_hold</code>.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_17" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    let rect2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    let rect3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">45</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Can rect1 hold rect2? {}"</span><span class="pun">,</span><span class="pln"> rect1</span><span class="pun">.</span><span class="pln">can_hold</span><span class="pun">(&amp;</span><span class="pln">rect2</span><span class="pun">));</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Can rect1 hold rect3? {}"</span><span class="pun">,</span><span class="pln"> rect1</span><span class="pun">.</span><span class="pln">can_hold</span><span class="pun">(&amp;</span><span class="pln">rect3</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 14: استخدام التابع can_hold الذي لم نكتبه بعد]
</p>

<p>
	سيبدو خرج الشيفرة البرمجية السابقة كما يلي، وذلك لأن كلا أبعاد النسخة <code>rect2</code> أصغر من أبعاد النسخة <code>rect1</code> إلا أن أبعاد النسخة <code>rect3</code> أكبر من النسخة <code>rect1</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_19" style=""><span class="typ">Can</span><span class="pln"> rect1 hold rect2</span><span class="pun">?</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="typ">Can</span><span class="pln"> rect1 hold rect3</span><span class="pun">?</span><span class="pln"> </span><span class="kwd">false</span></pre>

<p>
	نعلم أننا نريد تعريف تابع، ولذلك سنكتب ذلك ضمن الكتلة <code>impl Rectangle</code>، وسيكون اسم التابع <code>can_hold</code> وسيستعير نسخةً من <code>Rectangle</code> غير قابلة للتعديل مثل معامل، ويمكننا معرفة نوع المعامل بالنظر إلى السطر البرمجي الذي سيستدعي التابع، إذ يمرر الاستدعاء <code>rect1.can_hold(&amp;rect2)‎</code> الوسيط <code>‎&amp;rect2</code> وهو نُسخة من الهيكل <code>Rectangle</code> مُستعارة غير قابلة للتعديل، وهذا الأمر منطقي لأننا نريد فقط أن نقرأ بيانات النسخة <code>rect2</code> ولا حاجة لنا في التعديل عليها مما سيتطلب نسخةً مُستعارةً قابلة للتعديل، إذ نريد هنا أن تحتفظ الدالة <code>main</code> بملكية <code>rect2</code> حتى نستطيع استخدامها مجددًا بعد استدعاء التابع <code>can_hold</code>.
</p>

<p>
	ستكون القيمة المُعادة من التابع <code>can_hold</code> بوليانية boolean وسيتحقق تطبيقنا فيما إذا كان الطول والعرض الخاص بالمعامل <code>self</code> أكبر من الطول والعرض الخاص بنسخة <code>Rectangle</code> الأخرى. دعنا نُضيف التابع <code>can_hold</code> الجديد إلى كتلة <code>impl</code> الموجودة في الشيفرة 13 كما هو موضح في الشيفرة 15.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_21" style=""><span class="pln">impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn area</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">*</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">height
    </span><span class="pun">}</span><span class="pln">

    fn can_hold</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">height
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 15: تطبيق التابع can_hold ضمن الهيكل Rectangle الذي يأخذ نسخةً أخرى من الهيكل Rectangle بمثابة معامل]
</p>

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

<h2>
	الدوال المترابطة
</h2>

<p>
	تُدعى جميع الدوال المُعرّفة داخل الكتلة <code>impl</code> بالدوال المترابطة associated functions، وذلك لأنها مرتبطة بالنوع الموجود بعد <code>impl</code>، ويمكننا تعريف الدوال المترابطة التي لا تحتوي على المعامل الأول <code>self</code> (وبالتالي فهي لا تُعدّ توابعًا)، لأننا لا نحتاج إلى نسخة من النوع عند تنفيذها، وقد استخدمنا دالةً مشابهةً لهذه سابقًا، ألا وهي الدالة <code>String::from</code> والمعرّفة داخل النوع <code>String</code>.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_23" style=""><span class="pln">impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn square</span><span class="pun">(</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Self</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Self</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            width</span><span class="pun">:</span><span class="pln"> size</span><span class="pun">,</span><span class="pln">
            height</span><span class="pun">:</span><span class="pln"> size</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>Self</code> المفتاحية في النوع المُعاد ومتن الدالة بمثابة أسماء مستعارة للنوع الذي يظهر بعد الكلمة المفتاحية <code>impl</code>، والتي هي في حالتنا <code>Rectangle</code>.
</p>

<p>
	نستخدم <code>::</code> مع اسم الهيكل لاستدعاء الدالة المترابطة، والسطر <code>let sq = Rectangle::square(3)‎</code> هو مثال على ذلك، ويقع فضاء أسماء namespace هذه الدالة داخل الهيكل، ويُستخدم الرمز <code>::</code> لكلٍّ من الدوال المترابطة وفضاءات الأسماء المُنشأة من قبل الوحدات modules التي سنناقشها لاحقًا.
</p>

<h2>
	كتل impl متعددة
</h2>

<p>
	يمكن أن يحتوي كل هيكل على عدّة كُتَل <code>impl</code>، فعلى سبيل المثال الشيفرة 15 مكافئة للشيفرة 16 التالية التي تحتوي على كل تابع داخل كتلة <code>impl</code> مختلفة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_309_26" style=""><span class="pln">impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn area</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">*</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">height
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

impl </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fn can_hold</span><span class="pun">(&amp;</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> other</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> other</span><span class="pun">.</span><span class="pln">height
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 16: إعادة كتابة الشيفرة 15 باستخدام كتَل impl متعددة]
</p>

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

<p>
	‎ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch05-00-structs.html/" rel="external nofollow">Using Structs to Structure Related Data</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-enums-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1851/" rel="">التعدادات enums في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%84%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%B1%D8%B3%D8%AA-rust-r1849/" rel="">استخدام الهياكل structs لتنظيم البيانات في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1850</guid><pubDate>Fri, 13 Jan 2023 16:02:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x647;&#x64A;&#x627;&#x643;&#x644; structs &#x644;&#x62A;&#x646;&#x638;&#x64A;&#x645; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%84%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%B1%D8%B3%D8%AA-rust-r1849/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_01/1844821390_--structs------Rust.png.c3d095265efc5c154fba3076243e94c3.png" /></p>
<p>
	الهيكل struct أو البنية structure هو نوع بيانات مُخصّص يسمح لنا باستخدام عدة قيم بأسماء مختلفة في مجموعة واحدة ذات معنًى ما. يشبه <strong>الهيكل</strong> سمات attributes بيانات الكائن وفقًا لمفهوم <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a> أو <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>.
</p>

<p>
	سنقارن في هذا المقال بين الصفوف tuples والهياكل، ونستعرض كل منها بناءً على ما تعلمته سابقًا، وسنوضح الحالات التي يكون فيها استخدام الهياكل خيارًا أفضل لتجميع البيانات، وكذلك كيفية تعريف وإنشاء الهياكل، إضافةً إلى تعريف <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">الدوال</a> المرتبطة بها وبالأخص الدوال التي تحدد السلوك المرتبط بنوع الهيكل، والتي تُدعى <strong>التوابع methods</strong>. تُعدّ الهياكل والمُعدّدات enums (سنناقشها لاحقًا) من لبنات بناء نوع بيانات جديد ضمن نطاق برنامجك وذلك للاستفادة الكاملة من خاصية التحقق من الأنواع في رست عند وقت التصريف.
</p>

<h2>
	تعريف وإنشاء نسخة من الهياكل
</h2>

<p>
	تُشابه الهياكل الصفوف التي ناقشناها سابقًا في هذه السلسلة <a href="https://academy.hsoub.com/tags/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%20%D8%A8%D9%84%D8%BA%D8%A9%20%D8%B1%D8%B3%D8%AA/" rel="">البرمجة بلغة رست</a> وذلك من حيث تخزينها لعدة قيم مترابطة، إذ يمكن للهياكل أن تُخزّن أنواع بيانات مختلفة كما هو الحال في الصفوف، إلا أننا نسمّي كل جزء من البيانات ضمن الهيكل بحيث يكون الهدف منها واضحًا على عكس الصفوف، وهذا يعني أن الهياكل أكثر مرونة من الصفوف إذ أننا لا نعتمد على ترتيب البيانات بعد الآن لتحديد القيمة التي نريدها.
</p>

<p>
	نستخدم الكلمة المفتاحية <code>struct</code> لتعريف الهيكل ونُلحقها باسمه، ويجب أن يصِف اسم الهيكل استخدام البيانات التي يجمعها ويحتويها، ومن ثمّ نستخدم الأقواس المعقوصة curly brackets لتعريف أسماء وأنواع البيانات التي يحتويها الهيكل وتُدعى هذه البيانات باسم <strong>الحقول fields</strong>، فعلى سبيل المثال توضح الشيفرة 1 هيكلًا يحتوي داخله معلومات تخص معلومات عن حساب مستخدم.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_9" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">bool</span><span class="pun">,</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
    email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
    sign_in_count</span><span class="pun">:</span><span class="pln"> u64</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 1: تعريف الهيكل User]
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_11" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let user1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"someone@example.com"</span><span class="pun">),</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"someusername123"</span><span class="pun">),</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 2: إنشاء نسخة من الهيكل User]
</p>

<p>
	نستخدم النقطة (.) للحصول على قيمة محددة من هيكل ما؛ فإذا أردنا مثلًا الحصول على البريد الإلكتروني الخاص بالمستخدم فقط، فيمكننا كتابة <code>user1.email</code> عندما نريد استخدام تلك القيمة؛ وإذا كانت النسخة تلك قابلة للتعديل mutable، فيمكننا تغيير القيمة باستخدام الطريقة ذاتها أيضًا وإسناد الحقل إلى قيمة جديدة. توضح الشيفرة 3 كيفية تغيير القيمة في الحقل <code>email</code> الخاصة بالهيكل <code>User</code> القابل للتعديل.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_13" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut user1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"someone@example.com"</span><span class="pun">),</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"someusername123"</span><span class="pun">),</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    user1</span><span class="pun">.</span><span class="pln">email </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"anotheremail@example.com"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3: تعديل قيمة الحقل email الخاصة بنسخة من الهيكل User]
</p>

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

<p>
	توضح الشيفرة 4 الدالة <code>build_user</code> التي تُعيد نسخةً من الهيكل <code>User</code> باستخدام اسم مستخدم وبريد إلكتروني يُمرّران إليها، إذ يحصل الحقل <code>active</code> على القيمة <code>true</code>، بينما يحصل الحقل <code>sign_in_count</code> على القيمة "1".
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_15" style=""><span class="pln">fn build_user</span><span class="pun">(</span><span class="pln">email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln"> username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> email</span><span class="pun">,</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> username</span><span class="pun">,</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4: الدالة build_user التي تأخذ بريد إلكتروني واسم مستخدم ومن ثمّ تُعيد نسخة من الهيكل User]
</p>

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

<h3>
	ضبط قيمة حقول الهيكل بطريقة مختصرة
</h3>

<p>
	يُمكننا استخدام طريقة مختصرة في ضبط قيمة حقول الهيكل بما أن أسماء معاملات الدالة وأسماء حقول الهيكل متماثلة في الشيفرة 4، ولاستخدام هذه الطريقة نُعيد كتابة الدالة <code>build_user</code> بحيث تؤدي الغرض ذاته دون تكرار أي من أسماء الحقول <code>email</code> و <code>username</code> كما هو موضح في الشيفرة 5.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_17" style=""><span class="pln">fn build_user</span><span class="pun">(</span><span class="pln">email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln"> username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">,</span><span class="pln">
        username</span><span class="pun">,</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 5: دالة build_user تستخدم طريقة إسناد قيم الحقول المختصر لأن لمعاملات email و username الاسم ذاته لحقول الهيكل]
</p>

<p>
	نُنشئ هنا نسخةً جديدةً من الهيكل <code>User</code> الذي يحتوي على هيكل يدعى <code>email</code>، ونضبط قيمة الحقل <code>email</code> إلى قيمة المعامل <code>email</code> المُمرّر إلى الدالة <code>build_user</code>، وذلك لأن للحقل والمعامل الاسم ذاته وبذلك نستطيع كتابة <code>email</code> بدلًا من كتابة <code>email: email</code>.
</p>

<h3>
	إنشاء نسخ من نسخ أخرى عن طريق صيغة تحديث الهيكل
</h3>

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

<p>
	تظهر الشيفرة 6 كيفية إنشاء نسخة مستخدم <code>user</code> جديد في المستخدم <code>user2</code> بصورةٍ منتظمة دون استخدام صيغة تحديث الهيكل، إذ ضبطنا قيمة جديدة لحقل <code>email</code> بينما استخدمنا نفس القيم للمستخدم <code>user1</code> المُنشأ في الشيفرة 5.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_19" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">

    let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> user1</span><span class="pun">.</span><span class="pln">active</span><span class="pun">,</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> user1</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"another@example.com"</span><span class="pun">),</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> user1</span><span class="pun">.</span><span class="pln">sign_in_count</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 6: إنشاء نسخة user باستخدام إحدى قيم المستخدم user1]
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_21" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// --snip--</span><span class="pln">

    let user2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"another@example.com"</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">..</span><span class="pln">user1
    </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 7: استخدام صيغة تحديث الهيكل لضبط قيمة email لنسخة هيكل المستخدم User واستخدام بقية قيم المستخدم user1]
</p>

<p>
	تنشئ الشيفرة 7 أيضًا نسخةً في الهيكل <code>user2</code> بنفس قيم الحقول <code>username</code> و <code>active</code> و <code>sign_in_count</code> للهيكل <code>user1</code> ولكن لها قيمة <code>email</code> مختلفة. يجب أن يأتي المستخدم <code>user1..</code> أخيرًا ليدل على أن الحقول المتبقية يجب أن تحصل على قيمها من الحقول المقابلة في الهيكل <code>user1</code>، ولكن يمكننا تحديد قيم أي حقل من الحقول دون النظر إلى ترتيب الحقول الموجود في تعريف الهيكل.
</p>

<p>
	تستخدم صيغة تحديث الهيكل الإسناد <code>=</code>، لأنه ينقل البيانات تمامًا كما هو الحال في القسم "طرق التفاعل مع البيانات والمتغيرات: النقل" من مقال <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية ownership في لغة رست</a>. لم يعد بإمكاننا في هذا المثال استخدام <code>user1</code> بعد إنشاء <code>user2</code> بسبب نقل السلسلة النصية <code>String</code> الموجودة في الحقل <code>username</code> من المستخدم <code>user1</code> إلى <code>user2</code>. إذا أعطينا قيم سلسلة نصية جديدة إلى <code>user2</code> لكلا الحقلين <code>username</code> و <code>email</code> واستخدمنا فقط قيم الحقلين <code>active</code> و <code>sign_in_count</code> من الهيكل <code>user1</code>، سيبقى الهيكل <code>user1</code> في هذه الحالة صالحًا بعد إنشاء <code>user2</code>. تكون أنواع بيانات الحقلين <code>active</code> و <code>sign_in_count</code> بحيث تنفّذ السمة <code>Copy</code>، وبالتالي سينطبق هنا الأسلوب الذي ناقشناه في القسم الأول من الفصل المشار إليه آنفًا.
</p>

<h3>
	استخدام هياكل الصفوف دون حقول مسماة لإنشاء أنواع مختلفة
</h3>

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

<p>
	لتعريف هيكل صف، نبدأ بالكلمة المفتاحية <code>struct</code> ومن ثم اسم الصف متبوعًا بالأنواع الموجودة في الصف. على سبيل المثال، نعرّف هنا هيكلا صف بالاسم <code>Color</code> و <code>Point</code> ونستخدمهما:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_23" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Point</span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> i32</span><span class="pun">);</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let black </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Color</span><span class="pun">(</span><span class="lit">0</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">0</span><span class="pun">);</span><span class="pln">
    let origin </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Point</span><span class="pun">(</span><span class="lit">0</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">0</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أن <code>black</code> و <code>origin</code> من نوعين مختلفين، وذلك لأنهما نسختان من هياكل صف مختلفة، إذ يُعدّ كل هيكل تُعرفه نوعًا مختلفًا حتى لو كانت الحقول داخل الهيكل من نوع مماثل لهيكل آخر، على سبيل المثال، لا يمكن لدالة تأخذ النوع <code>Color</code> وسيطًا أن تأخذ النوع <code>Point</code> على الرغم من أن النوعين يتألفان من قيم من النوع <code>i32</code>. إضافةً لما سبق، يُماثل تصرف هياكل الصفوف تصرف الصفوف؛ إذ يمكنك تفكيكها إلى قطع متفرقة أو الوصول إلى قيم العناصر المختلفة بداخلها عن طريق استخدام النقطة (.) متبوعةً بدليل العنصر، وهكذا.
</p>

<h3>
	الهياكل الشبيهة بالوحدات بدون أي حقول
</h3>

<p>
	يُمكنك أيضًا تعريف هياكل لا تحتوي على أي حقول، وتدعى <strong>الهياكل الشبيهة بالوحدات unit-like structs</strong> لأنها مشابهة لنوع الوحدة unit type <code>()</code> الذي تحدثنا عنه <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">سابقًا</a>. يُمكن أن نستفيد من الهياكل الشبيهة بالوحدات عندما نريد تطبيق سمة trait على نوع ما ولكننا لا نملك أي بيانات نريد تخزينها داخل النوع، وسنناقش مفهوم السمات لاحقًا.
</p>

<p>
	إليك مثالًا عن تصريح وإنشاء نسخة من هيكل شبيه بالوحدات يدعى <code>AlwaysEqual</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_25" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">AlwaysEqual</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let subject </span><span class="pun">=</span><span class="pln"> </span><span class="typ">AlwaysEqual</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h3>
	ملكية بيانات الهيكل
</h3>

<p>
	استخدمنا في الشيفرة 1 النوع <code>String</code> في الهيكل <code>User</code> الموجود بدلًا عن استخدام نوع شريحة سلسلة نصية string slice type بالشكل <code>‎&amp;str</code>، وهذا استخدام مقصود لأننا نريد لكل نسخة من هذا الهيكل أن تمتلك جميع بياناتها وأن تكون بياناتها صالحة طالما الهيكل بكامله صالح.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_27" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">bool</span><span class="pun">,</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">,</span><span class="pln">
    email</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">,</span><span class="pln">
    sign_in_count</span><span class="pun">:</span><span class="pln"> u64</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let user1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        email</span><span class="pun">:</span><span class="pln"> </span><span class="str">"someone@example.com"</span><span class="pun">,</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">"someusername123"</span><span class="pun">,</span><span class="pln">
        active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        sign_in_count</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيشكو المصرّف ويخبرك أنه بحاجة محدّدات دورات الحياة lifetime specifiers:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_29" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> structs v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/structs)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0106</span><span class="pun">]:</span><span class="pln"> missing lifetime specifier
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">15</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">               </span><span class="pun">^</span><span class="pln"> expected named lifetime parameter
  </span><span class="pun">|</span><span class="pln">
help</span><span class="pun">:</span><span class="pln"> consider introducing a named lifetime parameter
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> </span><span class="pun">~</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">User</span><span class="pun">&lt;</span><span class="str">'</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">bool</span><span class="pun">,</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">~</span><span class="pln">     username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="str">'</span><span class="pln">a str</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">

error</span><span class="pun">[</span><span class="pln">E0106</span><span class="pun">]:</span><span class="pln"> missing lifetime specifier
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">4</span><span class="pun">:</span><span class="lit">12</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     email</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">^</span><span class="pln"> expected named lifetime parameter
  </span><span class="pun">|</span><span class="pln">
help</span><span class="pun">:</span><span class="pln"> consider introducing a named lifetime parameter
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> </span><span class="pun">~</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">User</span><span class="pun">&lt;</span><span class="str">'</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     active</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">bool</span><span class="pun">,</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">,</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">~</span><span class="pln">     email</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="str">'</span><span class="pln">a str</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0106</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">structs</span><span class="pun">`</span><span class="pln"> due to </span><span class="lit">2</span><span class="pln"> previous errors</span></pre>

<p>
	سنناقش كيفية حل هذه المشكلة لاحقًا، بحيث يمكنك تخزين المراجع في الهياكل، إلا أننا سنستخدم حاليًا الأنواع المملوكة owned types مثل <code>String</code> بدلًا عن المراجع مثل <code>‎&amp;str</code> لتجنب هذه المشكلة.
</p>

<h2>
	مثال على برنامج يستخدم الهياكل
</h2>

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

<p>
	نُنشئ مشروعًا ثنائيًا جديدًا باستخدام كارجو Cargo باسم "rectangles"، ويأخذ هذا البرنامج طول وعرض المستطيل بالبيكسل pixel ويحسب مساحة المستطيل. توضح الشيفرة 8 برنامجًا قصيرًا ينفذ ذلك بإحدى الطرق ضمن الملف "src/main.rs".
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_31" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let width1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
    let height1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln">

    println</span><span class="pun">!(</span><span class="pln">
        </span><span class="str">"The area of the rectangle is {} square pixels."</span><span class="pun">,</span><span class="pln">
        area</span><span class="pun">(</span><span class="pln">width1</span><span class="pun">,</span><span class="pln"> height1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn area</span><span class="pun">(</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
    width </span><span class="pun">*</span><span class="pln"> height
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 8: حساب مساحة المستطيل المُحدّد بمتغيّرَي الطول والعرض]
</p>

<p>
	دعنا الآن نُنفّذ البرنامج باستخدام الأمر <code>cargo run</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_33" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> rectangles v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/rectangles)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.42s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">rectangles</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> area of the rectangle is </span><span class="lit">1500</span><span class="pln"> square pixels</span><span class="pun">.</span></pre>

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

<p>
	تكمن المشكلة في شيفرتنا البرمجية الحالية في بصمة signature الدالة <code>area</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_35" style=""><span class="pln">fn area</span><span class="pun">(</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span></pre>

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

<h3>
	إعادة كتابة البرنامج باستخدام الصفوف
</h3>

<p>
	توضح الشيفرة 9 إصدارًا آخر من برنامجنا باستخدام الصفوف.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_37" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="pln">
        </span><span class="str">"The area of the rectangle is {} square pixels."</span><span class="pun">,</span><span class="pln">
        area</span><span class="pun">(</span><span class="pln">rect1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn area</span><span class="pun">(</span><span class="pln">dimensions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">u32</span><span class="pun">,</span><span class="pln"> u32</span><span class="pun">))</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
    dimensions</span><span class="pun">.</span><span class="lit">0</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> dimensions</span><span class="pun">.</span><span class="lit">1</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 9: تخزين طول وعرض المستطيل في صف]
</p>

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

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

<h3>
	إعادة كتابة البرامج باستخدام الهياكل وبوضوح أكبر
</h3>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_39" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="pln">
        </span><span class="str">"The area of the rectangle is {} square pixels."</span><span class="pun">,</span><span class="pln">
        area</span><span class="pun">(&amp;</span><span class="pln">rect1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn area</span><span class="pun">(</span><span class="pln">rectangle</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">Rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u32 </span><span class="pun">{</span><span class="pln">
    rectangle</span><span class="pun">.</span><span class="pln">width </span><span class="pun">*</span><span class="pln"> rectangle</span><span class="pun">.</span><span class="pln">height
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 10: تعريف الهيكل Rectangle]
</p>

<p>
	عرّفنا هنا هيكلًا اسمه <code>Rectangle</code>، ثم عرّفنا داخل الأقواس المعقوصة حقلَي الهيكل <code>width</code> و <code>height</code> من النوع <code>u32</code>، وننشئ بعدها نسخةً من الهيكل ضمن الدالة <code>main</code> بعرض 30 بيكسل وطول 50 بيكسل.
</p>

<p>
	الدالة <code>area</code> في هذا الإصدار من البرنامج معرّفة بمعامل واحد، وقد سمّيناه <code>rectangle</code> وهو من نوع الهيكل <code>Rectangle</code> القابل للإستعارة دون تعديل، وكما ذكرنا سابقًا، يمكننا استعارة borrow الهيكل بدلًا من الحصول على ملكيته وبهذه الطريقة تحافظ الدالة <code>main</code> على ملكيته ويمكننا استخدامه عن طريق النسخة <code>rect1</code> وهذا هو السبب في استخدامنا للرمز <code>&amp;</code> في بصمة الدالة وعند استدعائها.
</p>

<p>
	تُستخدَم الدالة <code>area</code> في الوصول لحقلَي نسخة الهيكل <code>Rectangle</code> وهُما <code>width</code> و <code>height</code>، وتدلّ بصمة الدالة هنا على ما نريد فعله بوضوح: احسب مساحة <code>Rectangle</code> باستخدام قيمتَي الحقلين <code>width</code> و <code>height</code>، وهذا يدلّ قارئ الشيفرة البرمجية على أن القيمتين مترابطتين فيما بينهما ويُعطي اسمًا واصفًا واضحًا لكل من القيمتُين بدلًا من استخدام قيم دليل الصف "0" و"1" كما سبق. وهذا الإصدار الأوضح حتى اللحظة.
</p>

<h3>
	بعض الإضافات المفيدة باستخدام السمات المشتقة
</h3>

<p>
	سيكون من المفيد أن نطبع نسخةً من الهيكل <code>Rectangle</code> عند تشخيص أخطاء برنامجنا للتحقق من قيم الحقول، نُحاول في الشيفرة 11 فعل ذلك باستخدام الماكرو <a href="https://doc.rust-lang.org/stable/std/macro.println.html" rel="external nofollow"><code>!println</code></a> كما عهدنا في المقالات السابقة إلا أن هذا الأمر لن ينجح.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_41" style=""><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"rect1 is {}"</span><span class="pun">,</span><span class="pln"> rect1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 11: محاولة طباعة نسخة من الهيكل Rectangle]
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_43" style=""><span class="pln">error</span><span class="pun">[</span><span class="pln">E0277</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Rectangle</span><span class="pun">`</span><span class="pln"> doesn</span><span class="str">'t implement `std::fmt::Display`</span></pre>

<p>
	يمكّننا الماكرو <code>!println</code> من تنسيق الخرج بعدّة أشكال، إلا أن التنسيق الافتراضي هو التنسيق المعروف باسم <code>Display</code> الذي يستخدم أسلوب كتابة الأقواس المعقوصة، وهو تنسيق موجّه لمستخدم البرنامج، وتستخدم أنواع البيانات الأولية primitive التي استعرضناها حتى الآن تنسيق <code>Display</code> افتراضيًا، وذلك لأن هناك طريقةً واحدةً لعرض القيمة "1" -أو أي قيمة نوع أولي آخر- للمستخدم، لكن الأمر مختلف مع الهياكل إذ أن هناك عدّة احتمالات لعرض البيانات التي بداخلها؛ هل تريد الطباعة مع الفواصل أم بدونها؟ هل تريد طباعة الأقواس المعقوصة؟ هل تريد عرض جميع الحقول؟ وبسبب هذا لا تحاول رست تخمين الطريقة التي نريد عرض الهيكل بها ولا يوجد أي تطبيق لطباعة الهيكل باستخدام النمط <code>Display</code> في الماكرو <code>println!‎</code> باستخدام الأقواس المعقوصة <code>{}</code>.
</p>

<p>
	إذا قرأنا رسالة الخطأ نجد الملاحظة المفيدة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_46" style=""><span class="pln">   </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the trait </span><span class="pun">`</span><span class="pln">std</span><span class="pun">::</span><span class="pln">fmt</span><span class="pun">::</span><span class="typ">Display</span><span class="pun">`</span><span class="pln"> is not implemented </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Rectangle</span><span class="pun">`</span><span class="pln">
   </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> in format strings you may be able to use </span><span class="pun">`{:?}`</span><span class="pln"> </span><span class="pun">(</span><span class="pln">or </span><span class="pun">{:#?}</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> pretty</span><span class="pun">-</span><span class="pln">print</span><span class="pun">)</span><span class="pln"> instead</span></pre>

<p>
	تخبرنا الملاحظة أنه يجب علينا استخدام تنسيق محدّد لطباعة الهيكل، لنجرّب ذلك! يصبح استدعاء الماكرو <code>println!‎</code> بالشكل التالي:
</p>

<pre class="ipsCode">println!("rect1 is {:?}, rect1);‎
</pre>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_48" style=""><span class="pln">error</span><span class="pun">[</span><span class="pln">E0277</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Rectangle</span><span class="pun">`</span><span class="pln"> doesn</span><span class="str">'t implement `Debug`</span></pre>

<p>
	إلا أن المصرف يساعدنا مجددًا بملاحظة مفيدة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_50" style=""><span class="pln">   </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> the trait </span><span class="pun">`</span><span class="typ">Debug</span><span class="pun">`</span><span class="pln"> is not implemented </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Rectangle</span><span class="pun">`</span><span class="pln">
   </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> add </span><span class="pun">`#[</span><span class="pln">derive</span><span class="pun">(</span><span class="typ">Debug</span><span class="pun">)]`</span><span class="pln"> to </span><span class="pun">`</span><span class="typ">Rectangle</span><span class="pun">`</span><span class="pln"> or manually </span><span class="pun">`</span><span class="pln">impl </span><span class="typ">Debug</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pun">`</span></pre>

<p>
	لا تُضمّن رست إمكانية طباعة المعلومات المتعلقة بتشخيص الأخطاء، إذ عليك أن تحدّد صراحةً أنك تريد استخدام هذه الوظيفة ضمن الهيكل الذي تريد طباعته، ولفعل ذلك نُضيف السمة الخارجية <code>‎#[derive(Debug)]‎</code> قبل تعريف الهيكل كما هو موضح في الشيفرة 12.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_52" style=""><span class="com">#[derive(Debug)]</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"rect1 is {:?}"</span><span class="pun">,</span><span class="pln"> rect1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 12: إضافة سمة للهيكل للحصول على السمة المُشتقة Debug وطباعة نسخة من الهيكل Rectangle باستخدام تنسيق تشخيص الأخطاء]
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_54" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> rectangles v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/rectangles)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.48s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">rectangles</span><span class="pun">`</span><span class="pln">
rect1 is </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pln"> </span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_56" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> rectangles v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/rectangles)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.48s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">rectangles</span><span class="pun">`</span><span class="pln">
rect1 is </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا طباعة القيم بطريقة أخرى، وهي باستخدام الماكرو <a href="https://doc.rust-lang.org/stable/std/macro.dbg.html" rel="external nofollow"><code>dbg!‎</code></a>، إذ يأخذ هذا الماكرو ملكية التعبير ويطبع الملف ورقم السطر الذي ورد فيه الماكرو، إضافةً إلى القيمة الناتجة من التعبير، ثمّ يُعيد الملكية للقيمة.
</p>

<p>
	<strong>ملاحظة</strong>: يطبع استدعاء الماكرو <code>dbg!‎</code> الخرج إلى مجرى أخطاء الطرفية القياسي standard error console stream أو كما يُدعى "stderr" على عكس الماكرو <code>println!‎</code> الذي يطبع الخرج إلى مجرى خرج الطرفية القياسي standard output console stream أو كما يُدعى "stdout"، وسنتحدث بصورةٍ موسعة عن "stderr" و "stdout" لاحقًا.
</p>

<p>
	إليك مثالًا عمّا سيبدو عليه برنامجنا إذا كُنّا مهتمين بمعرفة القيمة المُسندة إلى الحقل <code>width</code> إضافةً إلى قيم كامل الهيكل في النسخة <code>rect1</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_58" style=""><span class="com">#[derive(Debug)]</span><span class="pln">
</span><span class="kwd">struct</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> u32</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let scale </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    let rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        width</span><span class="pun">:</span><span class="pln"> dbg</span><span class="pun">!(</span><span class="lit">30</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> scale</span><span class="pun">),</span><span class="pln">
        height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    dbg</span><span class="pun">!(&amp;</span><span class="pln">rect1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكننا كتابة <code>dbg!‎</code> حول التعبير <code>30‎ *‎ scale</code> وسيحصل الحقل <code>width</code> على القيمة ذاتها في حالة عدم استخدامنا لاستدعاء <code>dbg!‎</code> هنا لأن <code>dbg!‎</code> يُعيد الملكية إلى قيمة التعبير، إلا أننا لا نريد للماكرو <code>dbg!‎</code> أن يأخذ ملكية <code>rect1</code>، لذلك سنستخدم مرجعًا إلى <code>rect1</code> في الاستدعاء الثاني. إليك ما سيبدو عليه الخرج عند تنفيذ البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7158_60" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> rectangles v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/rectangles)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.61s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">rectangles</span><span class="pun">`</span><span class="pln">
</span><span class="pun">[</span><span class="pln">src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">10</span><span class="pun">]</span><span class="pln"> </span><span class="lit">30</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> scale </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pln">
</span><span class="pun">[</span><span class="pln">src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">14</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">rect1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60</span><span class="pun">,</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكننا ملاحظة أن الجزء الأول من الخرج طُبِعَ نتيجةً للسطر البرمجي العاشر ضمن الملف src/main.rs، إذ أردنا تشخيص الخطأ في التعبير <code>30‎ *‎ scale</code> والقيمة 60 الناتجة عنه (يطبع تنسيق <code>Debug</code> فقط القيمة في حالة الأعداد الصحيحة)، بينما يطبع الاستدعاء الثاني للماكرو <code>dbg!‎</code> الوارد في السطر الرابع عشر ضمن الملف src/main.rs قيمة <code>‎&amp;rect1</code> الذي هو بدوره نسخةٌ من الهيكل <code>Rectangle</code>، ويستخدم الخرج تنسيق الطباعة <code>Debug</code> ضمن النوع <code>Rectangle</code>. يُمكن للماكرو <code>dbg!‎</code> أن يكون مفيدًا في العديد من الحالات التي تريد فيها معرفة ما الذي تفعله شيفرتك البرمجية.
</p>

<p>
	تزوّدنا رست بعدد من السمات الأخرى بجانب السمة <code>Debug</code>، ونستطيع استخدامها بواسطة السمة <code>derive</code> مما يُمكّننا من إضافة سلوكيات مفيدة إلى أنواع البيانات المُخصصة، نوضح السمات وسلوكياتها في الملحق (ت)، وسنغطي كيفية إنشاء سمات مُخصصة لاحقًا. هناك العديد من السمات الأخرى بجانب <code>derive</code>، للحصول على معلومات أكثر انظر <a href="https://doc.rust-lang.org/stable/reference/attributes.html" rel="external nofollow">Attributes</a>.
</p>

<p>
	الدالة <code>area</code> الموجودة لدينا الآن ضيقة الاستخدام، إذ أنها تحسب فقط مساحة المستطيل ومن المفيد أن نربط سلوكها بصورةٍ أكبر مع الهيكل <code>Rectangle</code> لأنها لا تعمل مع أي نوع آخر، وسننظر لاحقًا إلى إصدارات أخرى من هذا البرنامج التي ستحوّل الدالة <code>area</code> إلى تابع <code>area</code> ضمن النوع <code>Rectangle</code>.
</p>

<p>
	‎ترجمة -وبتصرف- لقسم من الفصل <a href="https://doc.rust-lang.org/stable/book/ch05-00-structs.html/" rel="external nofollow">Using Structs to Structure Related Data</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-methods-%D8%B6%D9%85%D9%86-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1850/" rel="">استخدام التوابع methods ضمن الهياكل structs في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">المراجع References والاستعارة Borrowing والشرائح Slices في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية Ownership في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1849</guid><pubDate>Sat, 07 Jan 2023 16:01:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x631;&#x627;&#x62C;&#x639; References &#x648;&#x627;&#x644;&#x627;&#x633;&#x62A;&#x639;&#x627;&#x631;&#x629; Borrowing &#x648;&#x627;&#x644;&#x634;&#x631;&#x627;&#x626;&#x62D; Slices &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A;</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/637350a6c1ab1_-References--Borrowing--Slices----Rust.png.b04888518819f055fc87ba16f85799bf.png" /></p>
<p>
	كانت مشكلتنا باستخدام الصف tuple في <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">المقالة السابقة</a> (الشيفرة 4-5) هو أنه علينا إعادة النوع <code>String</code> إلى القيمة المُستدعية ليتسنى لنا استخدام النوع <code>String</code> حتى بعد استدعاء الدالة <code>calculate_length</code>، وذلك لأن النوع <code>String</code> نُقل إلى <code>calculate_length</code>. بدلًا مما سبق يمكننا استخدام مرجع reference إلى القيمة <code>String</code>؛ والمرجع هو أشبه بالمؤشر pointer، إذ يُمثل عنوانًا يمكنك اتباعه للوصول إلى البيانات المخزنة ضمن العنوان المذكور، وتعود ملكية هذه البيانات إلى متغيرات أخرى مختلفة. من المضمون للمراجع -على عكس المؤشرات- أن تُشير إلى قيمة صالحة لنوع معين طوال دورة حياة المرجع.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_7" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let len </span><span class="pun">=</span><span class="pln"> calculate_length</span><span class="pun">(&amp;</span><span class="pln">s1</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The length of '{}' is {}."</span><span class="pun">,</span><span class="pln"> s1</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn calculate_length</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> usize </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">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أولًا أننا أزلنا الشيفرة البرمجية الخاصة بالصف في تصريح المتغير وقيمة الدالة المُعادة، كما أننا مررنا أيضًا <code>s1&amp;</code> إلى الدالة <code>calculate_length</code> وأخذنا في تعريفها <code>String&amp;</code> بدلًا من <code>String</code> وتُمثّل هذه الإشارة <code>&amp;</code> المرجع، وتسمح لك بالإشارة إلى قيمة دون أخذ ملكيتها، ويوضح الشكل التالي هذا المفهوم.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="112263" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-5.png.8b69082c062f8cdd91d2c1ba3db4d75c.png" rel="" data-fileext="png"><img alt="مخطط يوضح String s&amp; الذي يُشير إلى String s1" class="ipsImage ipsImage_thumbnailed" data-fileid="112263" data-unique="p05vsvngk" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-5.thumb.png.954088c8e594118279345645868a11b6.png"></a>
</p>

<p style="text-align: center;">
	[شكل 5: مخطط يوضح <code>String s&amp;</code> الذي يُشير إلى <code>String s1</code>]
</p>

<p>
	<strong>ملاحظة</strong>: عكس عملية المرجع باستخدام <code>&amp;</code> هي التحصيل dereferencing ويمكن تحقيقها باستخدام عامل التحصيل <code>*</code> وسنرى بعض استخدامات التحصيل بالإضافة لتفاصيل العملية لاحقًا.
</p>

<p>
	دعنا نأخذ نظرةً أعمق على استدعاء الدالة هنا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_10" style=""><span class="pln">    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let len </span><span class="pun">=</span><span class="pln"> calculate_length</span><span class="pun">(&amp;</span><span class="pln">s1</span><span class="pun">);</span></pre>

<p>
	تسمح لك الكتابة <code>s1&amp;</code> بإنشاء مرجع يشير إلى القيمة <code>s1</code> إلا أنه لا ينقل الملكية، وبالتالي -وبما أنه لا يملكها- لن تُسقط القيمة (باستخدام <code>drop</code>) التي يشير إليها عندما يتوقف المرجع عن استخدامها.
</p>

<p>
	وبالمثل، تستخدم شارة الدالة الرمز <code>&amp;</code> للإشارة إلى أن نوع المعامل <code>s</code> هو مرجع. دعنا نضيف بعض التعليقات التوضيحية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_12" style=""><span class="pln">fn calculate_length</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> usize </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫يمثل s مرجعًا إلى String</span><span class="pln">
    s</span><span class="pun">.</span><span class="pln">len</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫يخرج s من النطاق هنا إلا أنه لا يُسقط لأنه لا يمتلك القيمة التي يشير إليها</span></pre>

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

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

<p>
	ما الذي يحصل إذًا عندما نحاول التعديل على شيء مُستعار؟ جرّب تنفيذ الشيفرة 4-6 (تحذير: لن تعمل)
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_14" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    change</span><span class="pun">(&amp;</span><span class="pln">s</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn change</span><span class="pun">(</span><span class="pln">some_string</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    some_string</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="str">", world"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-6: محاولة التعديل على قيمة مُستعارة]
</p>

<p>
	وسيظهر الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_16" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0596</span><span class="pun">]:</span><span class="pln"> cannot borrow </span><span class="pun">`*</span><span class="pln">some_string</span><span class="pun">`</span><span class="pln"> as </span><span class="kwd">mutable</span><span class="pun">,</span><span class="pln"> as it is behind a </span><span class="pun">`&amp;`</span><span class="pln"> reference
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">8</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> fn change</span><span class="pun">(</span><span class="pln">some_string</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</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"> help</span><span class="pun">:</span><span class="pln"> consider changing </span><span class="kwd">this</span><span class="pln"> to be a </span><span class="kwd">mutable</span><span class="pln"> reference</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`&amp;</span><span class="pln">mut </span><span class="typ">String</span><span class="pun">`</span><span class="pln">
</span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     some_string</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="str">", 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">some_string</span><span class="pun">`</span><span class="pln"> is a </span><span class="pun">`&amp;`</span><span class="pln"> reference</span><span class="pun">,</span><span class="pln"> so the data it refers to cannot be borrowed as </span><span class="kwd">mutable</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0596</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<h2>
	المراجع القابلة للتعديل
</h2>

<p>
	يُمكننا تصحيح الشيفرة 4-6 السابقة لكي تسمح لنا بتعديل قيمة مُستعارة باستخدام تعديلات بسيطة، وذلك باستخدامنا مرجعًا قابلًا للتعديل mutable reference:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_18" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    change</span><span class="pun">(&amp;</span><span class="pln">mut s</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn change</span><span class="pun">(</span><span class="pln">some_string</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    some_string</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="str">", world"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	علينا أولًا أن نعدل المتغير <code>s</code> ليصبح <code>mut</code>، ثم نُنشئ مرجعًا قابلًا للتعديل باستخدام <code>mut s&amp;</code> عند نقطة استدعاء الدالة <code>chang</code>، ومن ثم تحديث شارة الدالة حتى تقبل مرجعًا قابلًا للتعديل بكتابة <code>some_string: &amp;mut String</code>، إذ يدلنا هذا بكل وضوح على أن الدالة <code>chang</code> ستُعدّل من القيمة التي استعارتها.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_20" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln">
    let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"{}, {}"</span><span class="pun">,</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> r2</span><span class="pun">);</span></pre>

<p>
	إليك الخطأ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_22" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0499</span><span class="pun">]:</span><span class="pln"> cannot borrow </span><span class="pun">`</span><span class="pln">s</span><span class="pun">`</span><span class="pln"> as </span><span class="kwd">mutable</span><span class="pln"> more than once at a time
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">5</span><span class="pun">:</span><span class="lit">14</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">------</span><span class="pln"> first </span><span class="kwd">mutable</span><span class="pln"> borrow occurs here
</span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">^^^^^^</span><span class="pln"> second </span><span class="kwd">mutable</span><span class="pln"> borrow occurs here
</span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     println</span><span class="pun">!(</span><span class="str">"{}, {}"</span><span class="pun">,</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> r2</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                        </span><span class="pun">--</span><span class="pln"> first borrow later used here

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0499</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<p>
	يسمح القيد الذي يمنع وجود عدة مراجع قابلة للتعديل تشير لنفس البيانات في نفس الوقت بتعديل البيانات ولكن بطريقة مُقيّدة جدًا، وهو شيء يعاني منه معظم متعلمي <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">لغة رست</a> الجدُد وذلك لأن معظم اللغات تسمح لك بتعديل ما تشاء. الميزة من هذا القيد هو أن رست تمنع سباق البيانات data races عند وقت التصريف، وسباق البيانات هو مشابه لحالة السباق race condition ويحدث عند حدوث أحد الحالات الثلاث:
</p>

<ul>
	<li>
		محاولة مؤشرين أو أكثر الوصول إلى نفس البيانات في نفس الوقت.
	</li>
	<li>
		استخدام واحد من المؤشرات على الأقل للكتابة إلى البيانات.
	</li>
	<li>
		عدم وجود آلية مُستخدمة لمزامنة الوصول إلى البيانات.
	</li>
</ul>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_25" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">{</span><span class="pln">
        let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="com">// يخرج‫ r1 من النطاق هنا وبالتالي يمكننا إنشاء مرجع جديد دون أي مشاكل</span><span class="pln">

    let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_27" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا توجد مشكلة</span><span class="pln">
    let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا توجد مشكلة</span><span class="pln">
    let r3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// هناك مشكلة كبيرة</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"{}, {}, and {}"</span><span class="pun">,</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> r2</span><span class="pun">,</span><span class="pln"> r3</span><span class="pun">);</span></pre>

<p>
	إليك الخطأ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_29" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0502</span><span class="pun">]:</span><span class="pln"> cannot borrow </span><span class="pun">`</span><span class="pln">s</span><span class="pun">`</span><span class="pln"> as </span><span class="kwd">mutable</span><span class="pln"> because it is also borrowed as immutable
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">6</span><span class="pun">:</span><span class="lit">14</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// no problem</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">--</span><span class="pln"> immutable borrow occurs here
</span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// no problem</span><span class="pln">
</span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let r3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// BIG PROBLEM</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">^^^^^^</span><span class="pln"> </span><span class="kwd">mutable</span><span class="pln"> borrow occurs here
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     println</span><span class="pun">!(</span><span class="str">"{}, {}, and {}"</span><span class="pun">,</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> r2</span><span class="pun">,</span><span class="pln"> r3</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                                </span><span class="pun">--</span><span class="pln"> immutable borrow later used here

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0502</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	كما أنه لا يمكننا إنشاء مرجع قابل للتعديل بينما لدينا مرجع غير قابل للتعديل يشير إلى القيمة ذاتها.
</p>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_31" style=""><span class="pln">    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let r1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا يوجد مشكلة</span><span class="pln">
    let r2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا يوجد مشكلة</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{} and {}"</span><span class="pun">,</span><span class="pln"> r1</span><span class="pun">,</span><span class="pln"> r2</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// لن يُستخدم المتغيرين‫ r1 و r2 بعد هذه النقطة</span><span class="pln">

    let r3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">mut s</span><span class="pun">;</span><span class="pln"> </span><span class="com">// لا يوجد مشكلة</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> r3</span><span class="pun">);</span></pre>

<p>
	ينتهي نطاق كل من المرجعَين غير القابلَين للتعديل <code>r1</code> و <code>r2</code> بعد <code>!println</code> وهي آخر نقطة لاستخدامهما قبل إنشاء المرجع القابل للتعديل <code>r3</code>. لا تتداخل النطاقات ولذلك تكون الشيفرة البرمجية صالحة، وتدعى قدرة المصرف على معرفة المراجع التي لا تُستخدم بعد الآن في نهاية النطاق باسم دورات الحياة غير المُعجمية Non-Lexical Lifetimes -أو اختصارًا NLL -ويمكنك القراءة عنها من <a href="https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#non-lexical-lifetimes" rel="external nofollow">rust-lang.org</a>.
</p>

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

<h2>
	المراجع المعلقة
</h2>

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

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_34" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let reference_to_nothing </span><span class="pun">=</span><span class="pln"> dangle</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn dangle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">&amp;</span><span class="pln">s
</span><span class="pun">}</span></pre>

<p>
	إليك الخطأ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_36" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0106</span><span class="pun">]:</span><span class="pln"> missing lifetime specifier
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">5</span><span class="pun">:</span><span class="lit">16</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"> fn dangle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</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"> expected named lifetime parameter
  </span><span class="pun">|</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> function</span><span class="str">'</span><span class="pln">s </span><span class="kwd">return</span><span class="pln"> type contains a borrowed value</span><span class="pun">,</span><span class="pln"> but there is no value </span><span class="kwd">for</span><span class="pln"> it to be borrowed from
help</span><span class="pun">:</span><span class="pln"> consider </span><span class="kwd">using</span><span class="pln"> the </span><span class="pun">`</span><span class="str">'</span><span class="kwd">static</span><span class="pun">`</span><span class="pln"> lifetime
  </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"> fn dangle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="str">'</span><span class="kwd">static</span><span class="pln"> </span><span class="typ">String</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="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0106</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_38" style=""><span class="kwd">this</span><span class="pln"> function</span><span class="str">'</span><span class="pln">s </span><span class="kwd">return</span><span class="pln"> type contains a borrowed value</span><span class="pun">,</span><span class="pln"> but there is no value
</span><span class="kwd">for</span><span class="pln"> it to be borrowed from</span></pre>

<p>
	دعنا نأخذ نظرةً أقرب لما يحدث في كل مرحلة من مراحل الدالة <code>dangle</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_40" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let reference_to_nothing </span><span class="pun">=</span><span class="pln"> dangle</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fn dangle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// تُعيد الدالة‫ dangle مرجعًا إلى النوع String</span><span class="pln">

    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يشكل s السلسلة String الجديدة</span><span class="pln">

    </span><span class="pun">&amp;</span><span class="pln">s </span><span class="com">// نُعيد المرجع إلى النوع‫ String واسمه s</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫يخرج s من النطاق هنا ويُسقَط وتُحرّر ذاكرته. خطر!</span></pre>

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

<p>
	يكمن الحل هنا بإعادة <code>String</code> مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_42" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let string </span><span class="pun">=</span><span class="pln"> no_dangle</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fn no_dangle</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

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

<p>
	يعمل هذا الحل دون أي مشاكل، إذ تُنقل الملكية ولا يُحرّر أي حيز من الذاكرة.
</p>

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

<p>
	دعنا نلخص أهم النقاط التي ناقشناها بخصوص المراجع:
</p>

<ul>
	<li>
		يُمكنك في نقطة من الزمن استخدام مرجع واحد قابل للتعديل <strong>أو</strong> عدة مراجع غير قابلة للتعديل.
	</li>
	<li>
		يجب أن تكون المراجع صالحة على الدوام.
	</li>
</ul>

<p>
	سننظر في الفقرات التالية إلى نوع مختلف من المراجع هو الشرائح slices.
</p>

<h2>
	نوع الشريحة
</h2>

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

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

<p>
	لنرى كيف يمكننا كتابة بصمة signature الدالة دون استخدام الشرائح، وذلك حتى نفهم المشكلة التي تحلها الشرائح:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_45" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">?</span></pre>

<p>
	للدالة <code>first_word</code> معامل <code>‎&amp;String</code>، وهذا ما لا بأس فيه لأننا لا نحتاج الملكية عليه، لكن ما الذي يجب أن تُعيده الدالة؟ لا توجد لدينا أي طريقة لتحديد جزء من السلسلة النصية، إلا أننا نستطيع إعادة دليل index نهاية الكلمة بالاستفادة من المسافة، لنجرّب هذه الطريقة كما هو موضح في الشيفرة 4-7.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_47" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> usize </span><span class="pun">{</span><span class="pln">
    let bytes </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">as_bytes</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> in bytes</span><span class="pun">.</span><span class="pln">iter</span><span class="pun">().</span><span class="pln">enumerate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> b</span><span class="str">' '</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> 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">

    s</span><span class="pun">.</span><span class="pln">len</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-7: الدالة <code>first_word</code> تُعيد قيمة دليل بحجم بايت إلى معامل <code>String</code>]
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_49" style=""><span class="pln">let bytes </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">as_bytes</span><span class="pun">();</span></pre>

<p>
	من ثم نُنشئ مُكرّرًا iterator على مصفوفة البايتات باستخدام تابع <code>iter</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_51" style=""><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> in bytes</span><span class="pun">.</span><span class="pln">iter</span><span class="pun">().</span><span class="pln">enumerate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	سنُناقش المُكرّرات بالتفصيل لاحقًا، أما الآن فكل ما عليك معرفته هو أن <code>iter</code> تابع يُعيد كل عنصر في تجميعة، وأن <code>enumerate</code> يُغلّف wraps نتيجة <code>iter</code> ويُعيد كل عنصر على أنه جزءٌ من الصف tuple بدلًا من ذلك، إذ يمثّل العنصر الأول من الصف المُعاد من التابع <code>enumerate</code> دليلًا، بينما يمثل العنصر الثاني مرجعًا إلى العنصر في التجميعة، وهذه الطريقة أسهل من حساب أدلة العناصر بأنفسنا.
</p>

<p>
	يُمكننا استخدام الأنماط patterns لتفكيك الصف وذلك بالنظر إلى أن التابع <code>enumerate</code> يُعيد صفًا، وسنناقش الأنماط بالتفصيل لاحقًا. نُحدد في حلقة <code>for</code> النمط الذي يحتوي على <code>i</code>، والذي يمثل الدليل الموجود في الصف و <code>‎&amp;item</code> للبايت الوحيد الموجود في الصف، ونستخدم <code>&amp;</code> في النمط لأننا نحصل على مرجع للعنصر من <code>iter().enumerate()‎.</code>.
</p>

<p>
	نبحث عن البايت الذي يمثل المسافة داخل حلقة <code>for</code> باستخدام البايت المجرّد، وإن وجدنا مسافةً نُعيد مكانها، وإلا فنعيد طول السلسلة النصية باستخدام<code>s.len()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_53" style=""><span class="pln">        </span><span class="kwd">if</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> b</span><span class="str">' '</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> 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">

    s</span><span class="pun">.</span><span class="pln">len</span><span class="pun">()</span></pre>

<p>
	لدينا طريقةٌ الآن لمعرفة دليل نهاية الكلمة الأولى في السلسلة النصية، إلا أن هناك مشكلةُ في هذه الطريقة؛ إذ أننا نُعيد النوع <code>usize</code> بصورةٍ منفردة إلا أنه ذو معنى فقط في سياق <code>‎&amp;String</code>، بكلمات أخرى، لا يوجد أي ضمان أن القيمة ستكون صالحة في المستقبل نظرًا لأنها قيمة منفصلة عن <code>String</code>. ألقِ نظرةً على الشيفرة 4-8 التي تستخدم الدالة <code>first_word</code> من الشيفرة 4-7.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_56" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello world"</span><span class="pun">);</span><span class="pln">

    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">s</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫ستُخزّن القيمة 5 في word</span><span class="pln">

    s</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln"> </span><span class="com">// تُفرغ هذه التعليمة السلسلة النصية وتجعلها مساوية إلى القيمة‫ “”</span><span class="pln">

    </span><span class="com">// ‫للمتغير word القيمة 5 هنا إلا أنه لا يوجد أي سلسلة نصية تجعل من هذه القيمة ذات معنى، وبالتالي القيمة عديمة الفائدة!</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-8: تخزين القيمة من استدعاء الدالة <code>first_word</code> ومن ثمّ تغيير محتويات <code>String]</code>
</p>

<p>
	يُصرَّف البرنامج السابق دون أي أخطاء وسيعمل دون مشاكل إذا استخدمنا <code>word</code> بعد استدعاء <code>s.clear()‎</code>، وذلك لأن <code>word</code> ليست مرتبطة بحالة <code>s</code>إطلاقًا، إذ ما زالت تحتوي <code>word</code> على القيمة 5 حتى بعد استدعاء <code>s.clear()‎</code>، ويمكننا استخدام القيمة 5 مع المتغير <code>s</code> حتى نحاول استخراج الكلمة الأولى إلا أن ذلك سيتسبب بخطأ لأن محتويات <code>s</code> تغيرت منذ أن خزّننا 5 في <code>word</code>.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_58" style=""><span class="pln">fn second_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">usize</span><span class="pun">,</span><span class="pln"> usize</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>

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

<p>
	لدى رست لحسن الحظ الحل لهذه المشكلة، وهي سلسلة الشرائح النصية string slices.
</p>

<h2>
	شرائح السلاسل النصية
</h2>

<p>
	شرائح السلاسل النصية هي مرجعٌ لجزء من النوع <code>String</code> وتُكتب بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_60" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello world"</span><span class="pun">);</span><span class="pln">

    let hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="lit">5</span><span class="pun">];</span><span class="pln">
    let world </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">6.</span><span class="pun">.</span><span class="lit">11</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نستخدم المرجع <code>hello</code> الذي يمثّل مرجعًا لجزء من النوع <code>String</code> بدلًا من استخدام مرجع لكامل النوع، والجزء مُحدّد باستخدام <code>[5..0]</code> بت. نُنشئ هنا شرائحًا باستخدام مجال باستخدام الأقواس وذلك بتحديد دليل البداية ودليل النهاية بالشكل التالي: <code>[starting_index..ending_index]</code>؛ إذ يُمثل <code>starting_index</code> موضع بداية الشريحة؛ بينما يمثل <code>ending_index</code> الموضع الذي يلي موضع نهاية الشريحة. يُخزّن هيكل بيانات الشريحة داخليًا كلًا من موضع البداية وطول الشريحة، الذي تحصل عليه من طرح <code>ending_index</code> من <code>starting_index</code>، لذا في حالة <code>let world = &amp;s[6..11]‎</code> نحصل على شريحة باسم <code>world</code> تحتوي على مؤشر يشير إلى البايت الموجود في الدليل 6 للسلسلة <code>s</code> بقيمة طول مساوية إلى 5.
</p>

<p>
	يوضح الشكل 6 العملية السابقة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="112264" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-6.png.cd73f0afee00b09da99278fd24bd8411.png" rel="" data-fileext="png"><img alt="شريحة سلسلة نصية تُشير إلى جز" class="ipsImage ipsImage_thumbnailed" data-fileid="112264" data-unique="b072idht7" style="width: 350px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-6.thumb.png.13a1c27e97e930a8d62dd42321cbc36d.png"></a>
</p>

<p style="text-align: center;">
	[شكل 6: شريحة سلسلة نصية تُشير إلى جزء من <code>String</code>]
</p>

<p>
	يُمكنك إهمال دليل البدء قبل النقطتين <code>..</code> في المجال إذا أردت البدء من الدليل صفر، أي أن الشريحتين التاليتن متماثلتان:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_64" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="lit">2</span><span class="pun">];</span><span class="pln">
let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[..</span><span class="lit">2</span><span class="pun">];</span></pre>

<p>
	كما يمكنك إهمال دليل النهاية إذا أردت أن تُضمّن السلسلة النصية إلى النهاية، أي أن الشريحتين التاليتين متماثلتان:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_66" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

let len </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">

let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">3.</span><span class="pun">.</span><span class="pln">len</span><span class="pun">];</span><span class="pln">
let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">3.</span><span class="pun">.];</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_68" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

let len </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">

let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="pln">len</span><span class="pun">];</span><span class="pln">
let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[..];</span></pre>

<p>
	<strong>ملاحظة:</strong> يجب أن تمثّل أدلّة شرائح السلاسل النصية محرفًا صالحًا من ترميز UTF-8، وإلا سيتوقف البرنامج ويعرض خطأً إذا حاولت إنشاء شريحة سلسلة نصية منتصف محرف متعدد البايتات multibyte character، ونفرض هنا في هذا القسم أن المحارف بترميز آسكي ASCII فقط بهدف البساطة، وسنناقش مفصّلًا التعامل مع محارف بترميز UTF-8 لاحقًا.
</p>

<p>
	بعد تعرّفنا لما سبق، دعنا نكتب دالة تُعيد شريحة نسميها <code>first_word</code>، والنوع الذي يمثّل شريحة السلسلة النصية هو <code>str&amp;</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_70" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span><span class="pln">
    let bytes </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">as_bytes</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> in bytes</span><span class="pun">.</span><span class="pln">iter</span><span class="pun">().</span><span class="pln">enumerate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> b</span><span class="str">' '</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[..]</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span></pre>

<p>
	نحصل في البرنامج السابق على دليل نهاية الكلمة بصورةٍ مشابهة لما فعلناه في الشيفرة 4-7 وذلك بالبحث عن أوّل ظهور لمسافة، وعندما نجد هذه المسافة نُعيد شريحة سلسلة نصية باستخدام بداية السلسلة النصية مثل دليل بداية ودليل المسافة مثل دليل نهاية.
</p>

<p>
	نحصل على قيمة واحدة متعلقة بالبيانات التي لدينا بعد استدعاء الدالة <code>first_word</code>، وتتألف القيمة من مرجع إلى نقطة البداية لشريحة السلسلة النصية وعدد العناصر في تلك الشريحة.
</p>

<p>
	يمكننا أن نجعل الدالة <code>second_word</code> تُعيد شريحة أيضًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_72" style=""><span class="pln">fn second_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span></pre>

<p>
	أصبح لدينا الآن <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهة برمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> واضحة صعب العبث فيها، إذ سيتأكد المصرّف من أن مراجع النوع <code>String</code> هي مراجع صالحة. أتتذكر الخطأ الذي واجهناه في البرنامج الموجود في الشيفرة 4-8 عندما حصلنا على دليل نهاية الكلمة الأولى ومن ثمّ مسحنا السلسلة النصية مما جعل الدليل غير صالح؟ كانت الشيفرة تلك غير صحيحة منطقيًا ولكننا لم نحصل على أي أخطاء مباشرة واضحة، وستظهر المشكلة لاحقًا إذا حاولت استخدام دليل السلسلة النصية الفارغة، إلا أن شرائح السلاسل النصية تجعل من هذا الخطأ مستحيلًا وستعلمنا بحدوث خطأ في شيفرتنا البرمجية في وقت مبكّر، وعلى سبيل المثال، نحصل على خطأ وقت التصريف إذا استخدمنا إصدار شريحة السلسلة النصية من الدالة <code>first_word</code>.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_75" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span><span class="pln">
    let bytes </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">as_bytes</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> in bytes</span><span class="pun">.</span><span class="pln">iter</span><span class="pun">().</span><span class="pln">enumerate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> b</span><span class="str">' '</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[..]</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello world"</span><span class="pun">);</span><span class="pln">

    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">s</span><span class="pun">);</span><span class="pln">

    s</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ‫خطأ!</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"the first word is: {}"</span><span class="pun">,</span><span class="pln"> word</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_3678_77" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0502</span><span class="pun">]:</span><span class="pln"> cannot borrow </span><span class="pun">`</span><span class="pln">s</span><span class="pun">`</span><span class="pln"> as </span><span class="kwd">mutable</span><span class="pln"> because it is also borrowed as immutable
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">18</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">16</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">s</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">                           </span><span class="pun">--</span><span class="pln"> immutable borrow occurs here
</span><span class="lit">17</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">18</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     s</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">();</span><span class="pln"> </span><span class="com">// error!</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">^^^^^^^^^</span><span class="pln"> </span><span class="kwd">mutable</span><span class="pln"> borrow occurs here
</span><span class="lit">19</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="lit">20</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     println</span><span class="pun">!(</span><span class="str">"the first word is: {}"</span><span class="pun">,</span><span class="pln"> word</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">                                       </span><span class="pun">----</span><span class="pln"> immutable borrow later used here

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0502</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	تذكّر من قواعد الاستعارة borrowing rules أنه لا يمكننا أخذ مرجع قابل للتعديل من شيء إذا كان لدينا مرجع غير قابل للتعديل لهذا الشيء مسبقًا، ولأن <code>clear</code> بحاجة لحذف محتويات <code>String</code>، فهي بحاجة للحصول على مرجع قابل للتعديل، يستخدم <code>println!‎</code> بعد الاستدعاء للدالة <code>clear</code> المرجع في <code>word</code>، لذلك لا بدّ للمرجع غير القابل للتعديل أن يكون صالحًا بحلول تلك النقطة ولذلك تمنع رست وجود مرجع قابل للتعديل في <code>clear</code> ومرجع غير قابل للتعديل في <code>word</code> في الوقت ذاته مما يتسبب بفشل عملية التصريف. لم تكتفي رست بجعل الواجهة البرمجية أسهل للتعامل بل أقصَت صنفًا كاملًا من الأخطاء ممكنة الحدوث عند وقت التصريف.
</p>

<h3>
	السلاسل النصية المجردة هي شرائح
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_79" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello, world!"</span><span class="pun">;</span></pre>

<p>
	نوع <code>s</code> هنا هو <code>‎&amp;str</code> وهي شريحة تُشير إلى جزء محدد من الملف الثنائي، وهذا السبب في كون السلاسل النصية غير قابلة للتعديل، وبالتالي يكون المرجع <code>‎&amp;str</code> مرجعًا غير قابل للتعديل.
</p>

<h3>
	شرائح السلاسل النصية مثل معاملات
</h3>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_81" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span></pre>

<p>
	قد يكتب مبرمج لغة رست خبير بصمة الدالة السابقة الموضحة في الشيفرة 4-9 بدلًا من ذلك والسبب في هذا هو أن البصمة السابقة تسمح لنا باستخدام الدالة ذاتها على قيمتَي <code>‎&amp;String</code> و <code>‎&amp;str</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_83" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-9: تحسين دالة <code>first_word</code> باستخدام شريحة سلسلة نصية لنوع المُعامل <code>s</code>]
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_85" style=""><span class="pln">fn first_word</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">str </span><span class="pun">{</span><span class="pln">
    let bytes </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">as_bytes</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> in bytes</span><span class="pun">.</span><span class="pln">iter</span><span class="pun">().</span><span class="pln">enumerate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> b</span><span class="str">' '</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">&amp;</span><span class="pln">s</span><span class="pun">[..]</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let my_string </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello world"</span><span class="pun">);</span><span class="pln">

    </span><span class="com">// ‫تعمل الدالة first_word على شرائح النوع String سواءً كانت شريحة جزئية أو شريحة تشكل كامل السلسلة</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">my_string</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="lit">6</span><span class="pun">]);</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">my_string</span><span class="pun">[..]);</span><span class="pln">
    </span><span class="com">// ‫تعمل الدالة first_word على مراجع النوع String والمساوية إلى كامل شرائح String</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">my_string</span><span class="pun">);</span><span class="pln">

    let my_string_literal </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="com">// ‫تعمل الدالة first_word على شرائح سلاسل نصية مجردة سواءً كانت مجردة أو جزئية</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">my_string_literal</span><span class="pun">[</span><span class="lit">0.</span><span class="pun">.</span><span class="lit">6</span><span class="pun">]);</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(&amp;</span><span class="pln">my_string_literal</span><span class="pun">[..]);</span><span class="pln">

    </span><span class="com">// بما أن السلاسل النصية المجردة هي شرائح سلاسل نصية بالأصل، فالتعليمة التالية تعمل أيضًا دون طريقة كتابة الشريحة</span><span class="pln">
    let word </span><span class="pun">=</span><span class="pln"> first_word</span><span class="pun">(</span><span class="pln">my_string_literal</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الشرائح الأخرى
</h2>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_87" style=""><span class="pln">let a </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3678_93" style=""><span class="pln">let a </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

let slice </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln">a</span><span class="pun">[</span><span class="lit">1.</span><span class="pun">.</span><span class="lit">3</span><span class="pun">];</span><span class="pln">

assert_eq</span><span class="pun">!(</span><span class="pln">slice</span><span class="pun">,</span><span class="pln"> </span><span class="pun">&amp;[</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>
	للشريحة النوع <code>‎&amp;[i32]‎</code> وتعمل بطريقة مماثلة لشريحة السلسلة النصية وذلك بتخزين مرجع للعنصر الأول وطول الشريحة، وستستخدم هذا النوع من الشرائح لكافة أنواع التجميعات الأخرى، وسنناقش هذه التجميعات بالتفصيل عندما نتحدث عن الأشعة لاحقًا.
</p>

<p>
	ترجمة -وبتصرف- لقسم من فصل <a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html/" rel="external nofollow">Understanding Ownership</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%87%D9%8A%D8%A7%D9%83%D9%84-structs-%D9%84%D8%AA%D9%86%D8%B8%D9%8A%D9%85-%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%B1%D8%B3%D8%AA-rust-r1849/" rel="">استخدام الهياكل structs لتنظيم البيانات في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">كيفية كتابة الدوال Functions والتعليقات Comments في لغة راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1787</guid><pubDate>Sat, 17 Dec 2022 16:05:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x644;&#x643;&#x64A;&#x629; Ownership &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A;</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/637345af7b9da_-ownership---.png.6d6f7344d162651a891440929b6b3579.png" /></p>
<p>
	المُلكية ownership هي مجموعة من القوانين التي تحدد كيف يُدير برنامج رست استخدام الذاكرة، ويتوجب على جميع البرامج أن تُدير الطريقة التي تستخدم فيها <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> عند تشغيلها. تلجأ بعض <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> إلى كانس المهملات garbage collector الذي يتفقد باستمرار الذاكرة غير المُستخدمة بعد الآن أثناء عمل البرنامج، بينما تعطي لغات البرمجة الأخرى مسؤولية تحديد الذاكرة وتحريرها للمبرمج مباشرةً، إلا أن رست تسلك طريقًا آخر ثالثًا؛ ألا وهو أن الذاكرة تُدار عبر نظام ملكية يحتوي على مجموعة من القوانين التي يتفقدها المصرّف، إذ لا يُصرّف البرنامج إذا حدث خرق لأحد هذه القوانين، ولن تبطئ أي من مزايا الملكية برنامجك عند تشغيله.
</p>

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

<p>
	ستحصل على أساس قوي في فهم المزايا التي تجعل من <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> لغة فريدة فور فهمك للملكية، وستتعلم في هذا المقال مفهوم الملكية بكتابة بعض الأمثلة التي تركز على <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-data-structures/" rel="">هيكل بيانات data structure</a> شائع جدًا هو السلاسل النصية strings.
</p>

<h2>
	المكدس والكومة
</h2>

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

<p>
	يمثل كلًا من المكدس والكومة أجزاءً متاحةً من الذاكرة لشيفرتك البرمجية حتى تستخدمها عند وقت التشغيل runtime، إلا أنهما مُهيكلان بطريقة مختلفة؛ إذ يُخزن المكدس القيم بالترتيب الذي وردت فيه ويُزيل القيم بالترتيب المعاكس، ويُشار إلى ذلك بمصطلح <strong>الداخل آخرًا، يخرج أولًا last in, first out</strong>. يمكنك التفكير بالمكدس وكأنه كومة من الأطباق، فعندما تضيف المزيد من الأطباق، فإنك تضيفها على قمة الكومة وعندما تريد إزالة طبق فعليك إزالة واحد من القمة، ولا يُمكنك إزالة الأطباق من المنتصف أو من القاع. تُسمى عملية إضافة البيانات بالدفع إلى المكدس pushing onto the stack بينما تُدعى عملية إزالة البيانات بالإزالة من المكدس popping off the stack، ويجب على جميع البيانات المخزنة في المكدس أن تكون من حجم معروف وثابت، بينما تُخزّن البيانات ذات الحجم غير المعروف عند وقت التصريف أو ذات الحجم الممكن أن يتغير في الكومة بدلًا من ذلك.
</p>

<p>
	الكومة هي الأقل تنظيمًا إذ يمكنك طلب مقدار معين من المساحة عند تخزين البيانات إليها، وعندها يجد محدد المساحة memory allocator حيزًا فارغًا في الكومة يتسع للحجم المطلوب، يعلّمه على أنه حيّز قيد الاستعمال، ثم يُعيد مؤشرًا pointer يشير إلى عنوان المساحة المحجوزة، وتدعى هذه العملية بحجز مساحة الكومة allocating on the heap وتُدعى في بعض الأحيان بحجز المساحة فقط (لا تُعد عملية إضافة البيانات إلى المكدس عملية حجز مساحة). بما أن المؤشر الذي يشير إلى الكومة من حجم معروف وثابت، يمكنك تخزينه في المكدس، وعندما تريد البيانات الفعلية من الكومة يجب عليك تتبع المؤشر. فكر بالأمر وكأنه أشبه بالجلوس في مطعم، إذ تصرّح عن عدد الأشخاص في مجموعتك عند دخولك إلى المطعم، ثم يبحث كادر المطعم عن طاولة تتسع للجميع ويقودك إليها، وإذا تأخر شخص ما عن المجموعة يمكنه سؤال كادر المطعم مجددًا ليقوده إلى الطاولة.
</p>

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

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

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

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

<h2>
	قوانين الملكية
</h2>

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

<ul>
	<li>
		لكل قيمة في رست مالك owner.
	</li>
	<li>
		يجب أن يكون لكل قيمة مالك واحد في نقطة معينة من الوقت.
	</li>
	<li>
		تُسقط القيمة عندما يخرج المالك من النطاق scope.
	</li>
</ul>

<h2>
	نطاق المتغير
</h2>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_12" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hello"</span><span class="pun">;</span></pre>

<p>
	يُشير المتغير <code>s</code> إلى السلسلة النصية المجردة، إذ أن قيمة السلسلة النصية مكتوبة بصورةٍ صريحة على أنها نص في برنامجنا، والمتغير هذا صالح من نقطة التصريح عنه إلى نهاية النطاق الحالي. توضح الشيفرة 4-1 البرنامج مع تعليقات توضح مكان صلاحية المتغير <code>s</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_14" style=""><span class="pln">    </span><span class="pun">{</span><span class="pln">                      </span><span class="com">// المتغير غير صالح هنا إذ لم يُصرّح عنه بعد</span><span class="pln">
        let s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hello"</span><span class="pun">;</span><span class="pln">   </span><span class="com">// المتغير صالح من هذه النقطة فصاعدًا</span><span class="pln">

        </span><span class="com">// ‪‪‫يمكننا استخدام s في العمليات هنا</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">                      </span><span class="com">// ‫انتهى النطاق بحلول هذه النقطة ولا يمكننا استخدام s</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-1: متغير والنطاق الذي يكون فيه صالحًا]
</p>

<p>
	بكلمات أخرى، هناك نقطتان مهمتان حاليًا:
</p>

<ul>
	<li>
		عندما يصبح المتغير <code>s</code> ضمن النطاق، يصبح صالحًا.
	</li>
	<li>
		يبقى المتغير صالحًا حتى مغادرته النطاق.
	</li>
</ul>

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

<h2>
	النوع String
</h2>

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

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

<p>
	رأينا مسبقًا السلاسل النصية المجردة (وهي السلاسل النصية المكتوبة بين علامتي تنصيص " " بصورةٍ صريحة)، إذ تُكتب قيمة السلسلة النصية يدويًا إلى البرنامج. السلاسل النصية المجردة مفيدةٌ إلا أنها غير مناسبة لكل الحالات، مثل تلك التي نريد فيها استخدام النص ويعود السبب في ذلك إلى أنها غير قابلة للتعديل immutable، والسبب الآخر هو أنه لا يمكننا معرفة قيمة كل سلسلة نصية عندما نكتب شيفرتنا البرمجية، فعلى سبيل المثال، ماذا لو أردنا أخذ الدخل من المستخدم وتخزينه؟ تملك رست لمثل هذه الحالات نوع سلسلة نصية آخر يدعى <code>String</code>، ويدير هذا النوع البيانات باستخدام الكومة، وبالتالي يمكنه تخزين كمية غير معروفة من النص عند وقت التصريف. يُمكنك إنشاء <code>String</code> من سلسلة نصية مجردة باستخدام دالة <code>from</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_16" style=""><span class="pln">let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span></pre>

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

<p>
	يُمكن تعديل mutate هذا النوع من السلاسل النصية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_18" style=""><span class="pln">let mut s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

s</span><span class="pun">.</span><span class="pln">push_str</span><span class="pun">(</span><span class="str">", world!"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// يُضيف‫ ()push_str سلسلةً نصية مجردة إلى النوع String</span><span class="pln">

println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫سيطبع هذا السطر `!hello, world`</span></pre>

<p>
	إذًا، ما الفارق هنا؟ كيف يمكننا تعديل النوع <code>String</code> بينما لا يمكننا تعديل السلاسل النصية المجردة؟ الفارق هنا هو بكيفية تعامل كل من النوعين مع الذاكرة.
</p>

<h2>
	الذاكرة وحجزها
</h2>

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

<p>
	نحتاج إلى تحديد مساحة من الذاكرة ضمن الكومة عند استخدام نوع <code>String</code> وذلك لدعم إمكانية تعديله وجعله سلسلةً نصيةً قابلة للزيادة والنقصان، بحيث تكون هذه المساحة التي تخزن البيانات غير معلومة الحجم عند وقت التصريف، وهذا يعني:
</p>

<ul>
	<li>
		يجب أن تُطلب الذاكرة من مُحدد الذاكرة عند وقت التشغيل.
	</li>
	<li>
		نحتاج طريقة لإعادة الذاكرة إلى محدد الذاكرة عندما ننتهي من استخدام <code>String</code> الخاص بنا.
	</li>
</ul>

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

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

<p>
	تسلك لغة رست سلوكًا مختلفًا، إذ تُحرر الذاكرة أوتوماتيكيًا عندما يغادر المتغير الذي يملك تلك الذاكرة النطاق. إليك إصدارًا من الشيفرة 4-1 نستخدم فيه النوع <code>String</code> بدلًا من السلسلة النصية المجردة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_20" style=""><span class="pln">    </span><span class="pun">{</span><span class="pln">
        let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫المتغير s صالح من هذه النقطة فصاعدًا</span><span class="pln">

        </span><span class="com">// يمكننا إنجاز العمليات باستخدام المتغير‫ s هنا</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">                                  </span><span class="com">// انتهى النطاق ولم يعد المتغير‫ s صالحًا</span></pre>

<p>
	نستعيد الذاكرة التي يستخدمها <code>String</code> من محدد الذاكرة عندما يخرج المتحول <code>s</code> من النطاق، إذ تستدعي رست دالةً مميزةً بالنيابة عنا عند خروج متحول ما من النطاق وهذه الدالة هي <code>drop</code>، وتُستدعى تلقائيًا عند الوصول إلى قوس الإغلاق المعقوص <code>{</code>.
</p>

<p>
	<strong>ملاحظة:</strong> يُدعى نمط تحرير الموارد في نهاية دورة حياة العنصر في <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> أحيانًا "اكتساب الموارد هو تهيئتها Resource Acquisition Is Initialization" -أو اختصارًا RAII- ودالة <code>drop</code> في رست هي مشابهة لأنماط RAII التي قد استخدمتها سابقًا.
</p>

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

<h3>
	طرق التفاعل مع البيانات والمتغيرات: النقل
</h3>

<p>
	يُمكن لعدة متغيرات أن تتفاعل مع نفس البيانات بطرق مختلفة في رست، دعنا ننظر إلى الشيفرة 4-2 على أنها مثال يستخدم عددًا صحيحًا.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_23" style=""><span class="pln">let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
let y </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-2: إسناد قيمة العدد الصحيح إلى المتغيرين x و y]
</p>

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

<p>
	لننظر الآن إلى إصدار <code>String</code> من الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_25" style=""><span class="pln">let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">
let s2 </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">;</span></pre>

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

<p>
	انظر إلى الشكل 1 لرؤية ما الذي يحصل بدقة للنوع <code>String</code>، إذ يتكون هذا النوع من ثلاثة أجزاء موضحة ضمن الجدول اليساري وهي المؤشر ptr الذي يشير إلى الذاكرة التي تُخزن السلسلة النصية وطول السلسلة النصية len وسعتها capacity، وتُخزّن مجموعة المعلومات هذه في المكدس، بينما يمثّل الجدول اليميني الذاكرة في الكومة التي تخزن محتوى السلسلة النصية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112255" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-1.png.1fab73dbcf9a118c46bd717e8ee2ea57.png" rel=""><img alt="مخطط توضيحي لما تبدو عليه الذاكرة عند استخدام String" class="ipsImage ipsImage_thumbnailed" data-fileid="112255" data-unique="e60b2ejr0" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-1.thumb.png.b7413ce17d9f56f0092f418621c111be.png"></a>
</p>

<p style="text-align: center;">
	[شكل 1: مخطط توضيحي لما تبدو عليه الذاكرة عند استخدام <code>String</code> يخزن القيمة "hello" المُسندة إلى <code>s1</code>]
</p>

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

<p>
	تُنسخ بيانات <code>String</code> عندما نُسند <code>s1</code> إلى <code>s2</code>، وهذا يعني أننا ننسخ المؤشر والطول والسعة الموجودين في المكدس ولا ننسخ البيانات الموجودة في الكومة التي يشير إليها المؤشر، بكلمات أخرى، يبدو تمثيل الذاكرة بعد النسخ كما هو موضح في الشكل 2.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112257" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-2.png.ba400dfa732d054b466777e3123f7f4e.png" rel=""><img alt="تمثيل الذاكرة للمتغير s2 الذي يحتوي على نسخة من مؤشر وطول وسعة s1" class="ipsImage ipsImage_thumbnailed" data-fileid="112257" data-unique="a0d8stx0v" style="width: 350px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-2.thumb.png.77ec0d958723b862e2a7086f7c19ccac.png"></a>
</p>

<p style="text-align: center;">
	[شكل 2: تمثيل الذاكرة للمتغير <code>s2</code> الذي يحتوي على نسخة من مؤشر وطول وسعة <code>s1</code>]
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112258" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-3.png.0268846498df2953376e2868c200328f.png" rel=""><img alt="احتمال آخر لما قد تبدو عليه الذاكرة بعد عملية الإسناد s2 = s1" class="ipsImage ipsImage_thumbnailed" data-fileid="112258" data-unique="jgze7bf57" style="width: 350px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-3.thumb.png.65c0d9769cd30b457a1ecb3adea34fd5.png"></a>
</p>

<p style="text-align: center;">
	[شكل 3: احتمال آخر لما قد تبدو عليه الذاكرة بعد عملية الإسناد <code>s2 = s1</code> وذلك إذا نسخت رست محتويات الكومة أيضًا]
</p>

<p>
	قلنا سابقًا أن رست تستدعي الدالة <code>drop</code> تلقائيًا عندما يغادر متغيرٌ ما النطاق، وتحرّر الذاكرة الموجودة في الكومة لذلك المتغير، إلا أن الشكل 2 يوضح أن كلا المؤشرين يشيران إلى الموقع ذاته، ويمثّل هذا مشكلةً واضحة، إذ عندما يغادر كلًا من <code>s1</code> و<code>s2</code> النطاق، فهذا يعني أن الذاكرة في الكومة ستُحرّر مرتين، وهذا خطأ تحرير ذاكرة مزدوج double free error شائع، وهو خطأ من أخطاء أمان الذاكرة الذي ذكرناه سابقًا، إذ يؤدي تحرير الذاكرة نفسها مرتين إلى فساد في الذاكرة مما قد يسبب ثغرات أمنية.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_33" style=""><span class="pln">let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">
let s2 </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">;</span><span class="pln">

println</span><span class="pun">!(</span><span class="str">"{}, world!"</span><span class="pun">,</span><span class="pln"> s1</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_35" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> ownership v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/ownership)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0382</span><span class="pun">]:</span><span class="pln"> borrow of moved value</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">s1</span><span class="pun">`</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">5</span><span class="pun">:</span><span class="lit">28</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">         </span><span class="pun">--</span><span class="pln"> move occurs because </span><span class="pun">`</span><span class="pln">s1</span><span class="pun">`</span><span class="pln"> has type </span><span class="pun">`</span><span class="typ">String</span><span class="pun">`,</span><span class="pln"> which does not implement the </span><span class="pun">`</span><span class="typ">Copy</span><span class="pun">`</span><span class="pln"> trait
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let s2 </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">--</span><span class="pln"> value moved here
</span><span class="lit">4</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">     println</span><span class="pun">!(</span><span class="str">"{}, world!"</span><span class="pun">,</span><span class="pln"> s1</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">                            </span><span class="pun">^^</span><span class="pln"> value borrowed here after move
  </span><span class="pun">|</span><span class="pln">
  </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> error originates in the macro </span><span class="pun">`</span><span class="pln">$crate</span><span class="pun">::</span><span class="pln">format_args_nl</span><span class="pun">`</span><span class="pln"> </span><span class="pun">(</span><span class="pln">in </span><span class="typ">Nightly</span><span class="pln"> builds</span><span class="pun">,</span><span class="pln"> run with </span><span class="pun">-</span><span class="pln">Z macro</span><span class="pun">-</span><span class="pln">backtrace </span><span class="kwd">for</span><span class="pln"> more info</span><span class="pun">)</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0382</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">ownership</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	لعلك سمعت بمصطلح النسخ السطحي shallow copy والنسخ العميق deep copy خلال عملك على لغة برمجة أخرى؛ إذ يُشير مصطلح النسخ السطحي إلى عملية نسخ مؤشر وطول وسعة السلسلة النصية دون البيانات الموجودة في الكومة، إلا أن رست تسمّي هذه العملية بالنقل move لأنها تُزيل صلاحية المتغير الأول. في هذا المثال، نقول أن <code>s1</code> نُقِلَ إلى <code>s2</code>، والنتيجة الحاصلة موضحة في الشكل 4.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112259" href="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-4.png.075b071272b013ea99469342d2dc94b8.png" rel=""><img alt="تمثيل الذاكرة بعد إزالة صلاحية المتغير s1" class="ipsImage ipsImage_thumbnailed" data-fileid="112259" data-unique="cls94ngja" style="width: 350px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/Figure-4-4.thumb.png.cdd9500f64ec6ac570b087effcf8cbe1.png"></a>
</p>

<p style="text-align: center;">
	[شكل 4: تمثيل الذاكرة بعد إزالة صلاحية المتغير <code>s1</code>]
</p>

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

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

<h3>
	طرق التفاعل مع البيانات والمتغيرات: الاستنساخ
</h3>

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

<p>
	إليك مثالًا عمليًا عن تابع <code>clone</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_38" style=""><span class="pln">    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">
    let s2 </span><span class="pun">=</span><span class="pln"> s1</span><span class="pun">.</span><span class="pln">clone</span><span class="pun">();</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"s1 = {}, s2 = {}"</span><span class="pun">,</span><span class="pln"> s1</span><span class="pun">,</span><span class="pln"> s2</span><span class="pun">);</span></pre>

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

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

<h3>
	نسخ بيانات المكدس فقط
</h3>

<p>
	هناك تفصيلٌ آخر لم نتكلم بخصوصه بعد. تستخدم الشيفرة البرمجية التالية (جزء من الشيفرة 4-2) أعدادًا صحيحة، وهي شيفرة برمجية صالحة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_40" style=""><span class="pln">let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
let y </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">

println</span><span class="pun">!(</span><span class="str">"x = {}, y = {}"</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span></pre>

<p>
	إلا أن الشيفرة البرمجية تبدو مناقضة لما تعلمنا مسبقًا، إذ أن <code>x</code> صالح ولم يُنقل إلى المتغير <code>y</code> على الرغم من عدم استدعائنا للتابع <code>clone</code>.
</p>

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

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

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

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

<ul>
	<li>
		كل أنواع الأعداد الصحيحة مثل <code>u32</code>.
	</li>
	<li>
		الأنواع البوليانية <code>bool</code> التي تحمل القيمتين <code>true</code> و <code>false</code>.
	</li>
	<li>
		جميع أنواع أعداد الفاصلة العشرية مثل <code>f64</code>.
	</li>
	<li>
		نوع المحرف <code>char</code>.
	</li>
	<li>
		الصفوف tuples إذا احتوى الصف فقط على الأنواع التي يمكن تطبيق <code>Copy</code> عليها، على سبيل المثال يُمكن تطبيق <code>Copy</code> على <code>(i32, i32)</code>، بينما لا يمكن تطبيق <code>Copy</code> على <code>(i32, String)</code>.
	</li>
</ul>

<h2>
	الملكية والدوال
</h2>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_42" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">  </span><span class="com">// ‫يدخل المتغير s إلى النطاق</span><span class="pln">

    takes_ownership</span><span class="pun">(</span><span class="pln">s</span><span class="pun">);</span><span class="pln">             </span><span class="com">// ‫تُنقل قيمة s إلى الدالة ولا تعود صالحة للاستخدام هنا</span><span class="pln">

    let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">                      </span><span class="com">// ‫يدخل المتغير x إلى النطاق</span><span class="pln">

    makes_copy</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln">                  
</span><span class="com">// ‫يُنقل المتغير x إلى الدالة إلا أن i32 تملك السمة Copy لذا من الممكن استخدام المتغير x بعد هذه النقطة</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> </span><span class="com">// يغادر المتحول x خارج النطاق ولا شيء مميز يحدث لأن قيمة s نُقِلَت</span><span class="pln">

fn takes_ownership</span><span class="pun">(</span><span class="pln">some_string</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫يدخل المتغير some_string إلى النطاق</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> some_string</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫يُغادر المتغير some_string النطاق هنا وتُستدعى drop، وتُحرر الذاكرة الخاصة بالمتغير</span><span class="pln">

fn makes_copy</span><span class="pun">(</span><span class="pln">some_integer</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// يدخل المتغير‫ some_integer إلى النطاق</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"{}"</span><span class="pun">,</span><span class="pln"> some_integer</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="com">// ‫يغادر المتغير some_integer النطاق ولا يحصل أي شيء مثير للاهتمام</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-3: استخدام الدوال مع الملكية والنطاق]
</p>

<p>
	ستعرض لنا رست خطأً عند وقت التصريف إذا حاولنا استخدام <code>a</code> بعد استدعاء <code>takes_ownership</code>، ويحمينا هذا التفقد الساكن static من بعض الأخطاء. حاول إضافة شيفرة برمجية تستخدم <code>s</code> و <code>x</code> إلى الدالة <code>main</code> ولاحظ أين يمكنك استخدامهما وأين تمنعك قوانين الملكية من استخدامهما.
</p>

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

<p>
	يُمكن أن تحول عملية إعادة القيمة ملكيتها أيضًا، توضح الشيفرة 4-4 مثالًا عن دالة تُعيد قيمة بصورةٍ مشابهة للشيفرة 4-3.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_44" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s1 </span><span class="pun">=</span><span class="pln"> gives_ownership</span><span class="pun">();</span><span class="pln">         </span><span class="com">// تنقل الدالة‫ gives_ownership قيمتها المُعادة إلى s1</span><span class="pln">


    let s2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">     </span><span class="com">// ‫يدخل المتغير s2 إلى النطاق</span><span class="pln">

    let s3 </span><span class="pun">=</span><span class="pln"> takes_and_gives_back</span><span class="pun">(</span><span class="pln">s2</span><span class="pun">);</span><span class="pln">  
</span><span class="com">// يُنقل المتغير‫ s2 إلى  takes_and_gives_back الذي ينقل قيمته المعادة بدوره إلى المتغير s3</span><span class="pln">

</span><span class="pun">}</span><span class="pln"> 
</span><span class="com">// يُغادر‫ s3 النطاق من هنا ويُحرر من الذاكرة باستخدام drop، ولا يحصل أي شيء للمتغير s2 لأنه نُقل، بينما يغادر s1 النطاق أيضًا ويُحرر من الذاكرة باستخدام drop</span><span class="pln">

fn gives_ownership</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span><span class="pln">             </span><span class="com">// تنقل الدالة‫ gives_ownership قيمتها المعادة إلى الدالة التي استدعتها</span><span class="pln">

    let some_string </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"yours"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// ‫يدخل المتغير some_string إلى النطاق</span><span class="pln">

    some_string                              </span><span class="com">// ‫يُعاد some_string ويُنقل إلى الدالة المُستدعاة</span><span class="pln">

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

</span><span class="com">// تأخذ هذه الدالة سلسلة نصية وتُعيد سلسلة نصية أخرى</span><span class="pln">
fn takes_and_gives_back</span><span class="pun">(</span><span class="pln">a_string</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// ‫يدخل a_string إلى النطاق </span><span class="pln">

    a_string  </span><span class="com">// ‫يُعاد a_string ويُنقل إلى الدالة المُستدعاة</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-4: تحويل ملكية القيمة المُعادة]
</p>

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

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

<p>
	تسمح لنا رست بإعادة عدّة قيم باستخدام مجموعة كما هو موضح في الشيفرة 4-5.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8463_46" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let s1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">from</span><span class="pun">(</span><span class="str">"hello"</span><span class="pun">);</span><span class="pln">

    let </span><span class="pun">(</span><span class="pln">s2</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> calculate_length</span><span class="pun">(</span><span class="pln">s1</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The length of '{}' is {}."</span><span class="pun">,</span><span class="pln"> s2</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn calculate_length</span><span class="pun">(</span><span class="pln">s</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> usize</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let length </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"> </span><span class="com">// يُعيد‫ ()len طول السلسلة النصية</span><span class="pln">

    </span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4-5: إعادة الملكية إلى المعاملات]
</p>

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

<p>
	ترجمة -وبتصرف- لقسم من فصل <a href="https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html" rel="external nofollow">Understanding Ownership</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AC%D8%B9-references-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D8%A9-borrowing-%D9%88%D8%A7%D9%84%D8%B4%D8%B1%D8%A7%D8%A6%D8%AD-slices-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1787/" rel="">المراجع References والاستعارة Borrowing والشرائح Slices في لغة رست</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">كيفية كتابة الدوال Functions والتعليقات Comments في لغة راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1786</guid><pubDate>Sat, 10 Dec 2022 16:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x628;&#x633;&#x64A;&#x631; &#x62A;&#x646;&#x641;&#x64A;&#x630; &#x628;&#x631;&#x627;&#x645;&#x62C; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%B3%D8%AA-rust-r1785/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/63733fb606f62_---Flow-Control---Rust.png.2e79d2c0407c5a89067b009d15d5f445.png" /></p>
<p>
	تُعد القدرة على تشغيل جزء من الشيفرة البرمجية إذا تحقق شرط ما، أو تشغيل جزء ما باستمرار بينما الشرط محقق من الكتل الأساسية في بناء أي <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغة برمجة</a>، كما تُعد تعابير <code>if</code> و<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية</a> أكثر اللبنات التي تسمح لك بالتحكم بسير تنفيذ البرنامج flow control في البرامج المكتوبة بلغة راست.
</p>

<h2>
	تعابير if الشرطية
</h2>

<p>
	يسمح لك تعبير <code>if</code> بتفرعة branch شيفرتك البرمجية بحسب الشروط، ويُمكنك كتابة الشرط بحيث "إذا تحقق هذا الشرط فنفذ هذا الجزء من الشيفرة البرمجية، وإلا فلا تنفّذه".
</p>

<p>
	أنشئ مشروعًا جديدًا باسم "branches" في المجلد "projects"، إذ سنستخدم هذا المشروع للتعرف على تعابير <code>if</code>. عدّل الملف "src/main.rs" ليحتوي على الشيفرة التالية:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_10" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"condition was true"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"condition was false"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

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

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_12" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.31s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">branches</span><span class="pun">`</span><span class="pln">
condition was </span><span class="kwd">true</span></pre>

<p>
	دعنا نُغيّر قيمة <code>number</code> إلى قيمة أخرى تجعل قيمة الشرط <code>false</code> ونرى ما الذي سيحدث:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_14" style=""><span class="pln">let number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span></pre>

<p>
	نفّذ البرنامج مجددًا، وانظر إلى الخرج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_16" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.31s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">branches</span><span class="pun">`</span><span class="pln">
condition was </span><span class="kwd">false</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_18" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"number was three"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُقيَّم شرط <code>if</code> إلى القيمة 3 هذه المرة، ويعرض لنا راست الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_20" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0308</span><span class="pun">]:</span><span class="pln"> mismatched types
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">4</span><span class="pun">:</span><span class="lit">8</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">        </span><span class="pun">^^^^^^</span><span class="pln"> expected </span><span class="pun">`</span><span class="kwd">bool</span><span class="pun">`,</span><span class="pln"> found integer

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0308</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">branches</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	يُشير الخطأ إلى أن راست توقّع تلقي قيمة من نوع <code>bool</code> إلا أنه حصل على قيمة عدد صحيح integer. لا تُحوّل راست الأنواع غير البوليانية إلى أنواع بوليانية بعكس لغات البرمجة الأخرى، مثل <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>، إذ عليك أن تكون دقيقًا بكتابة شرط تعليمة <code>if</code> ليكون تعبيرًا يُقيَّم إلى قيمة بوليانية، على سبيل المثال إن أردنا لكتلة تعليمة <code>if</code> أن تعمل فقط في حالة كان الرقم لا يساوي الصفر فيمكننا تغيير التعبير كما يلي:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_24" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> number </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">
        println</span><span class="pun">!(</span><span class="str">"number was something other than zero"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيطبع تشغيل الشيفرة البرمجية السابقة "number was something other than zero".
</p>

<h3>
	التعامل مع عدة شروط باستخدام else if
</h3>

<p>
	يُمكنك استخدام عدة شروط باستخدام <code>if</code> و <code>else</code> في تعابير <code>else if</code>، على سبيل المثال:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_26" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">%</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"number is divisible by 4"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">%</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"number is divisible by 3"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> number </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"number is divisible by 2"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"number is not divisible by 4, 3, or 2"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_28" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.31s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">branches</span><span class="pun">`</span><span class="pln">
number is divisible by </span><span class="lit">3</span></pre>

<p>
	يتحقَّق البرنامج عند تنفيذه من كل تعبير <code>if</code> فيما إذا كان مُحقًًقًا ويُنفّذ أول متن شرط يُحقّق، لاحظ أنه على الرغم من قابلية قسمة 6 على 2 إلا أننا لم نرى الخرج <code>number is divisible by 2</code>، أو الخرج <code>number is not divisible by 4, 3, or 2</code> من كتلة التعليمة <code>else</code>، وذلك لأن <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">راست</a> تُنفّذ الكتلة الأولى التي تحقق الشرط فقط وحالما تجد هذه الكتلة، فإنها لا تتفقّد تحقق الشروط الأخرى التي تلي تلك الكتلة.
</p>

<p>
	قد يسبب استخدام الكثير من تعابير <code>else if</code> الفوضى في شيفرتك البرمجية، لذا إذا كان لديك أكثر من تعبير واحد، تأكد من إعادة النظر إلى شيفرتك البرمجية ومحاولة تحسينها، وسنناقش لاحقًا هيكل تفرعي branching construct في راست يُدعى <code>match</code> وقد صُمّم لهذه الحالات خصيصًا.
</p>

<h3>
	استخدام if في تعليمة let
</h3>

<p>
	يُمكننا استخدام <code>if</code> في الجانب الأيمن من تعليمة <code>let</code> بالنظر إلى أنها تعبير وإسناد النتيجة إلى متغير كما توضح الشيفرة 3-2.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_31" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let condition </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    let number </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> condition </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="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of number is: {number}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3-2: إسناد نتيجة تعبير if إلى متغير]
</p>

<p>
	يُسند المتغير <code>number</code> إلى قيمة بناءً على نتيجة تعبير <code>if</code>، نفّذ الشيفرة البرمجية السابقة ولاحظ النتيجة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_33" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.30s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">branches</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span></pre>

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

<p>
	نجد في الشيفرة 2 نتيجة كل من ذراع <code>if</code> و <code>else</code>، إذ تُمثّل القيمة النوع الصحيح <code>i32</code>. نحصل على خطأ إذا كانت الأنواع غير متوافقة كما هو الحال في المثال التالي:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_35" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let condition </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

    let number </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> condition </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="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"six"</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of number is: {number}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_37" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> branches v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/branches)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0308</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">`</span><span class="kwd">if</span><span class="pun">`</span><span class="pln"> and </span><span class="pun">`</span><span class="kwd">else</span><span class="pun">`</span><span class="pln"> have incompatible types
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">4</span><span class="pun">:</span><span class="lit">44</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let number </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> condition </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="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"six"</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"> expected integer</span><span class="pun">,</span><span class="pln"> found </span><span class="pun">`&amp;</span><span class="pln">str</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">                                 expected because of </span><span class="kwd">this</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0308</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">branches</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<h2>
	التكرار باستخدام الحلقات
</h2>

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

<p>
	لراست ثلاثة أنواع من الحلقات، هي: <code>loop</code> و <code>while</code> و <code>for</code>، دعنا نجرّب كل منها.
</p>

<h3>
	تكرار الشيفرة البرمجية باستخدام loop
</h3>

<p>
	تُعلِم الكلمة المفتاحية <code>loop</code> راست بوجوب تنفيذ جزء من الشيفرة البرمجية على نحوٍ متكرر إلى الأبد أو لحين تحديد التوقف بصورةٍ صريحة.
</p>

<p>
	على سبيل المثال، عدّل محتويات الملف "src/main.rs" في مجلد مشروعنا الجديد "loops" ليحتوي على الشيفرة البرمجية التالية:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_39" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"again!"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما نُشغّل البرنامج السابق سنجد النص "again!‎" مطبوعًا مرةً بعد الأخرى باستمرار إلى أن نوقف البرنامج يدويًا، ونستطيع إيقافه باستخدام اختصار لوحة المفاتيح "ctrl-c"، إذ تدعم معظم الطرفيات هذا الاختصار لإيقاف البرنامج في حال تكرار حلقة للأبد. جرّب الأمر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_41" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> loops v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/loops)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.29s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">loops</span><span class="pun">`</span><span class="pln">
again</span><span class="pun">!</span><span class="pln">
again</span><span class="pun">!</span><span class="pln">
again</span><span class="pun">!</span><span class="pln">
again</span><span class="pun">!</span><span class="pln">
</span><span class="pun">^</span><span class="typ">Cagain</span><span class="pun">!</span></pre>

<p>
	يُمثل الرمز <code>‎^C</code> الموضع الذي ضغطت فيه على الاختصار "ctrl-c"، وقد تجد الكلمة <code>again!‎</code> مطبوعةً بعد <code>‎^C</code> أو قد لا تجدها بحسب مكان التنفيذ ضمن الشيفرة البرمجية عند ضغطك على إشارة المقاطعة interrupt signal.
</p>

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

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

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_43" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

    let result </span><span class="pun">=</span><span class="pln"> loop </span><span class="pun">{</span><span class="pln">
        counter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> counter </span><span class="pun">==</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">break</span><span class="pln"> counter </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="pln">
    </span><span class="pun">};</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The result is {result}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نُصرّح عن متغير باسم <code>counter</code> ونُهيّئه بالقيمة "0" قبل الحلقة التكرارية، ثم نصرح عن متغير باسم <code>result</code> لتخزين القيمة المُعادة من الحلقة. نُضيف 1 إلى المتغير <code>counter</code> عند كل تكرار للحلقة ومن ثم نتحقق فيما إذا كان المتغير <code>counter</code> مساويًا إلى القيمة 10، وعندما يتحقق هذا الشرط نستخدم الكلمة المفتاحية <code>break</code> مع القيمة <code>counter * 2</code>، ونستخدم بعد الحلقة فاصلة منقوطة لإنهاء التعليمة التي تُسند القيمة إلى <code>result</code>، وأخيرًا نطبع القيمة <code>result</code> التي تكون في هذه الحالة مساويةً إلى 20.
</p>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_45" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="str">'</span><span class="pln">counting_up</span><span class="pun">:</span><span class="pln"> loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"count = {count}"</span><span class="pun">);</span><span class="pln">
        let mut remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">

        loop </span><span class="pun">{</span><span class="pln">
            println</span><span class="pun">!(</span><span class="str">"remaining = {remaining}"</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> remaining </span><span class="pun">==</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> count </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">break</span><span class="pln"> </span><span class="str">'</span><span class="pln">counting_up</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            remaining </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"End count = {count}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	للحلقة الخارجية التسمية <code>‎'counting_up</code> وستعدّ من 0 إلى 2، بينما تعدّ الحلقة الداخلية عديمة التسمية من 10 إلى 9. لا تُحدد <code>break</code> الأولى أي تسمية لذلك ستغادر الحلقة الداخلية فقط، بينما ستغادر تعليمة <code>break 'counting_up</code> الحلقة الخارجية، وتطبع الشيفرة البرمجية السابقة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_47" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> loops v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/loops)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.58s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">loops</span><span class="pun">`</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
remaining </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span></pre>

<h3>
	الحلقات الشرطية باستخدام while
</h3>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_49" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">while</span><span class="pln"> number </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">
        println</span><span class="pun">!(</span><span class="str">"{number}!"</span><span class="pun">);</span><span class="pln">

        number </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"LIFTOFF!!!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3-3: استخدام حلقة while لتنفيذ شيفرة برمجية عند تحقق شرط ما]
</p>

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

<h3>
	استخدام for مع تجميعة Collection
</h3>

<p>
	يمكنك اختيار البنية <code>while</code> للانتقال بين عناصر التجميعة مثل المصفوفات. توضح الشيفرة 3-4 ذلك الاستخدام بطباعة كل عنصر في المصفوفة <code>a</code>.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_51" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let a </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">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">];</span><span class="pln">
    let mut index </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">while</span><span class="pln"> index </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"the value is: {}"</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">index</span><span class="pun">]);</span><span class="pln">

        index </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 4: الانتقال بين عناصر التجميعة باستخدام حلقة while]
</p>

<p>
	إليك الشيفرة البرمجية التي تنتقل بين عناصر المصفوفة، إذ تبدأ من الدليل "0" وتنتقل إلى ما يليه لحد الوصول إلى الدليل الأخير في المصفوفة (أي عندما يكون <code>index &lt; 5</code> غير محقق). سيطبع تنفيذ الشيفرة السابقة عناصر المصفوفة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_53" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> loops v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/loops)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.32s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">loops</span><span class="pun">`</span><span class="pln">
the value is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
the value is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pln">
the value is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
the value is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40</span><span class="pln">
the value is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span></pre>

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

<p>
	سلوك البرنامج معرض للخطأ، فقد يهلع البرنامج إذا كانت قيمة الدليل أو الشرط الذي يُفحص خاطئة، على سبيل المثال إذا استبدلنا تعريف المصفوفة <code>a</code> ليكون لها أربعة عناصر ولكننا نسينا تحديث الشرط إلى <code>while index &lt; 4</code>، ستهلع الشيفرة البرمجية، كما أن هذا السلوك بطيء لأن المصرف يُضيف شيفرة برمجية عند وقت التشغيل لإنجاز التحقق من الشرط فيما إذا كان الدليل خارج حدود المصفوفة عند كل تكرار ضمن الحلقة. بدلًا من ذلك، يمكننا استخدام حلقة <code>for</code> وتنفيذ شيفرة برمجية لكل عنصر في التجميعة، وتبدو الحلقة بالشكل الموضح في الشيفرة 3-5.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_55" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let a </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">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">];</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> element in a </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"the value is: {element}"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3-5: الانتقال بين عناصر التجميعة باستخدام حلقة for]
</p>

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

<p>
	لست مضطرًا لتغيير أي شيفرة برمجية باستخدام حلقة <code>for</code> إذا عدلت رقم العناصر في المصفوفة، الأمر الذي ستضطر لفعله في حال استخدامك للشيفرة 3-4.
</p>

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

<p>
	إليك ما سيبدو عليه برنامج العد التنازلي باستخدام حلقة <code>for</code> وتابع آخر لم نتكلم عنه بعد وهو <code>rev</code>، المُستخدم في عكس المجال:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3308_57" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> number in </span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.</span><span class="lit">4</span><span class="pun">).</span><span class="pln">rev</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"{number}!"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"LIFTOFF!!!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تبدو هذه الشيفرة البرمجية أفضل، أليس كذلك؟
</p>

<p>
	ترجمة -وبتصرف- للقسم <a href="https://doc.rust-lang.org/stable/book/ch03-05-control-flow.html/" rel="external nofollow">Control Flow</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language.</a>
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D9%84%D9%83%D9%8A%D8%A9-ownership-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1786/" rel="">الملكية Ownership في لغة رست</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">كيفية كتابة الدوال Functions والتعليقات Comments في لغة راست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1785</guid><pubDate>Sat, 03 Dec 2022 16:08:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; Functions &#x648;&#x627;&#x644;&#x62A;&#x639;&#x644;&#x64A;&#x642;&#x627;&#x62A; Comments &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1781/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636a512901efe_---Functions--Comments----Rust.png.350dd9a24aa9ff832e67ff58e054bd16.png" /></p>
<p>
	تنتشر الدوال في معظم شيفرات راست البرمجية، وقد رأيت سابقًا واحدةً من أهم الدوال في اللغة ألا وهي دالة <code>main</code> وهي نقطة البداية للكثير من البرامج، كما أنك رأيت أيضًا الكلمة المفتاحية <code>fn</code> التي تسمح لك بالتصريح عن دالةٍ جديدة.
</p>

<p>
	تستخدم شيفرة راست البرمجية نمط الثعبان snake case نمطًا اصطلاحيًا لأسماء الدوال و<a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات</a>، إذ تكون الأحرف في هذا النمط جميعها أحرف صغيرة ويفصل ما بين الكلمة والأخرى شرطة سفلية. إليك برنامجًا يحتوي على مثال لتعريف دالة:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_7" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Hello, world!"</span><span class="pun">);</span><span class="pln">

    another_function</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn another_function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Another function."</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نعرّف الدالة في راست بإدخال الكلمة <code>fn</code> متبوعةً باسم الدالة يليها قوسين هلاليّين parentheses <code>()</code>، بينما تُخبر الأقواس المعقوفة curly brackets <code>{}</code> المصرف بموضع بداية وانتهاء متن الدالة.
</p>

<p>
	يُمكننا استدعاء أي دالة عرفناها سابقًا بإدخال اسمها متبوعًا بقوسين هلاليّين، وبما أن الدالة <code>another_function</code> مُعرفةٌ في البرنامج، يمكننا استدعائها من داخل الدالة <code>main</code>. لاحظ أننا عرفنا <code>another_function</code> بعد دالة <code>main</code> في الشيفرة البرمجية إلا أنه يمكننا تعريفها قبلها أيضًا، إذ لا تُبالي راست بموضع تعريف الدوال طالما يوجد التعريف داخل النطاق scope الذي استدعيت الدالة منه.
</p>

<p>
	دعنا نبدأ مشروعًا ثنائيًا binary project جديدًا باسم "functions" للنظر إلى الدوال بتعمّق أكبر، وضع مثال "another_function" السابق في ملف "src/main.rs" ونفّذه. يجب أن يظهر لك الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_9" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.28s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">functions</span><span class="pun">`</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Another</span><span class="pln"> function</span><span class="pun">.</span></pre>

<p>
	تُنفّذ هذه السطور البرمجية بالترتيب التي ظهرت فيه في الدالة <code>main</code>، أي تُطبع الرسالة "Hello, world!‎" أولًا، ثم تُستدعى الدالة <code>another_function</code> وتُطبع رسالتها.
</p>

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

<p>
	يُمكننا تعريف الدوال بحيث تحتوي على معاملات parameters، وهي متغيرات خاصة تنتمي إلى بصمة الدالة function's signature، ويُمكنك استخدام قيم فعلية لهذه الدالة عند احتوائها على معاملات، وتُدعى هذه القيم بالوسطاء arguments إلا أنه غالبًا ما يُستخدم المصطلحان معامل ووسيط بصورةٍ تبادلية interchangeably لأي من المتغيرات في تعريف الدالة أو القيم الفعلية المُمرّرة للدالة عند استدعائها.
</p>

<p>
	نُضيف معاملًا في هذا الإصدار من الدالة <code>another_function</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_11" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    another_function</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn another_function</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</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_8503_13" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">1.21s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">functions</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span></pre>

<p>
	يحتوي تصريح الدالة <code>another_function</code> على معامل واحد باسم <code>x</code> وهو من النوع <code>i32</code>، بالتالي يضع الماكرو ‏<code>!println</code> القيمة 5 عند تمريرها إلى الدالة مثل قيمة للمعامل <code>x</code> في تنسيق السلسلة النصية.
</p>

<p>
	يجب التصريح عن نوع كل معامل في بصمة الدالة، وهذا أمر متعمد في تصميم <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">لغة راست</a>؛ إذ يعني تحديد أنواع المعاملات في تعريف الدالة أن المُصرّف لن يحتاج منك استخدامها في مكان آخر ضمن الشيفرة البرمجية لمعرفة النوع الذي قصدته، وبالتالي يستطيع المصرف إعطاء رسائل خطأ ذات معنًى ومضمون مُساعد أكثر إذا كان يعلم نوع المعاملات التي تأخذها الدالة.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_15" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    print_labeled_measurement</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'h'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn print_labeled_measurement</span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">,</span><span class="pln"> unit_label</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">char</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The measurement is: {value}{unit_label}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُنشئ هذا المثال دالةً باسم <code>print_labeled_measurment</code> بمعاملَين، إذ يسمى المعامل الأول <code>value</code> وهو من النوع <code>i32</code>، بينما يسمى النوع الثاني <code>unit_label</code> وهو من النوع <code>char</code>، وتطبع الدالة نصًّا يحتوي على كل من <code>value</code> و <code>unit_label</code>.
</p>

<p>
	دعنا نجرّب تشغيل الشيفرة البرمجية السابقة، وذلك باستبدال البرنامج الموجود حاليًا في ملف "src/main.rs" لمشروع "function" بالشيفرة البرمجية السابقة، وتشغيل البرنامج باستخدام <code>cargo run</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_17" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.31s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">functions</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> measurement is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5h</span></pre>

<p>
	نحصل على الخرج السابق طالما استُدعيت الدالة بالقيمة "5" للمعامل <code>value</code> والقيمة 'h' للمعامل <code>unit_label</code>.
</p>

<h2>
	التعابير والتعليمات
</h2>

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

<p>
	التعليمات هي توجيهات تُجري عمليات ما ولا تُعيد قيمةً، بينما تُقيّم التعابير إلى قيمة ناتجة. دعنا ننظر إلى بعض الأمثلة.
</p>

<p>
	استخدمنا في الحقيقة سابقًا كلًا من التعابير والتعليمات، وذلك بإنشاء متغير وإسناد قيمة إليه باستخدام الكلمة المفتاحية <code>let</code>، نجد في الشيفرة 3-1 التعليمة <code>let y = 6;‎</code>.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_19" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[الشيفرة 3-1: تعريف دالة main يحتوي على تعليمة واحدة]
</p>

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

<p>
	لا تُعيد التعليمات أي قيمة، لذلك لا يُمكنك إسناد تعليمة <code>let</code> إلى متغير آخر كما نحاول في المثال التالي، إذ ستحصل على خطأ:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_21" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</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_8503_23" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> expected expression</span><span class="pun">,</span><span class="pln"> found statement </span><span class="pun">(`</span><span class="pln">let</span><span class="pun">`)</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">14</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</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"> note</span><span class="pun">:</span><span class="pln"> variable declaration </span><span class="kwd">using</span><span class="pln"> </span><span class="pun">`</span><span class="pln">let</span><span class="pun">`</span><span class="pln"> is a statement

error</span><span class="pun">[</span><span class="pln">E0658</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">let</span><span class="pun">`</span><span class="pln"> expressions in </span><span class="kwd">this</span><span class="pln"> position are unstable
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">14</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</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"> note</span><span class="pun">:</span><span class="pln"> see issue </span><span class="com">#53667 &lt;https://github.com/rust-lang/rust/issues/53667&gt; for more information</span><span class="pln">

warning</span><span class="pun">:</span><span class="pln"> unnecessary parentheses around assigned value
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">13</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</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"> note</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`#[</span><span class="pln">warn</span><span class="pun">(</span><span class="pln">unused_parens</span><span class="pun">)]`</span><span class="pln"> on by </span><span class="kwd">default</span><span class="pln">
help</span><span class="pun">:</span><span class="pln"> remove these parentheses
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let y </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">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> 

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0658</span><span class="pun">`.</span><span class="pln">
warning</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">functions</span><span class="pun">`</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bin </span><span class="str">"functions"</span><span class="pun">)</span><span class="pln"> generated </span><span class="lit">1</span><span class="pln"> warning
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">functions</span><span class="pun">`</span><span class="pln"> due to </span><span class="lit">2</span><span class="pln"> previous errors</span><span class="pun">;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> warning emitted</span></pre>

<p>
	لا تُعيد التعليمة <code>let y = 6</code> أي قيمة، لذا لا يوجد هناك أي قيمة لإسنادها إلى <code>x</code>، وهذا الأمر مختلفٌ عن باقي <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> مثل <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/ruby/%D8%AA%D8%B9%D8%B1%D9%91%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-ruby-r636/" rel="">روبي Ruby</a> إذ تُعيد عملية الإسناد في هذه اللغات قيمة الإسناد، وبالتالي يمكنك كتابة التعليمة <code>x = y = 6</code> بحيث تُسند القيمة 6 إلى كل من <code>x</code> و <code>y</code> إلا أن هذا الأمر لا ينطبق في راست.
</p>

<p>
	تُقيِّم وتركّب التعابير معظم الشيفرة البرمجية التي ستكتبها في راست، خُذ على سبيل المثال تعبير العملية الحسابية <code>5 + 6</code>، التي تُقيّم إلى القيمة 11. يمكن أن تكون التعابير جزءًا من التعليمات، ففي الشيفرة 3-1 تُمثّل 6 في التعليمة <code>let y = 6;‎</code> تعبيرًا يُقيّم إلى القيمة 6. يُعد كل من استدعاء الدالة واستدعاء الماكرو وإنشاء نطاق جديد باستخدام الأقواس المعقوفة تعبيرًا، على سبيل المثال:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_28" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let y </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
        x </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">

    println</span><span class="pun">!(</span><span class="str">"The value of y is: {y}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	التعبير التالي هو جزءٌ يُقيم إلى القيمة 4:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_30" style=""><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
    x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h2>
	الدوال التي تعيد قيمة
</h2>

<p>
	يُمكن للدوال أن تُعيد قيمًا إلى الشيفرة البرمجية التي استدعتها، ولا نُسمّي القيم المُعادة هذه إلا أنه يجب التصريح عن نوعها باستخدام السهم <code>&lt;-</code>. القيمة المُعادة من الدالة في راست هي مرادف لقيمة التعبير الأخير في متن الدالة، ويُمكنك إعادة قيمة مبكرًا من الدالة باستخدام الكلمة المفتاحية <code>return</code> وتحديد القيمة بعدها، إلا أن معظم الدوال تُعيد قيمة التعبير الأخير ضمنيًا. إليك مثالًا عن دالة تُعيد قيمة:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_32" style=""><span class="pln">fn five</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> i32 </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">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> five</span><span class="pun">();</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يوجد في الدالة <code>five</code> أي استدعاءات، أو ماكرو، أو حتى تعليمة <code>let</code>، بل فقط الرقم 5، وتلك دالة صالحة في لغة راست. لاحظ أن نوع القيمة المُعادة من الدالة مُحدّد أيضًا بكتابة <code>‎-&gt; i32</code>. يجب أن تحصل على الخرج التالي إذا جرّبت تشغيل الشيفرة البرمجية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_34" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.30s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">functions</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span></pre>

<p>
	تُمثّل القيمة 5 في الدالة <code>five</code> القيمة المُعادة من الدالة، وهذا السبب في تحديدنا لنوع القيمة المعادة بالنوع <code>i32</code>، لكن دعنا ننظر إلى الدالة بتعمُّق أكبر، إذ يوجد جزآن مُهمّان، هما:
</p>

<p>
	أولًا، يوضح السطر <code>let x = five();‎</code> أننا نستخدم القيمة المُعادة من الدالة لإسنادها مثل قيمة أولية للمتغير وبما أن الدالة تُعيد القيمة 5، فهذا الأمر موافق لكتابة السطر البرمجي التالي تمامًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_36" style=""><span class="pln">let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span></pre>

<p>
	ثانيًا، لا تحتوي الدالة <code>five</code> أي معاملات وتُعرِّف نوع القيمة المعادة، إلا أن متن الدالة يحتوي على القيمة 5 بصورةٍ منفردة دون فاصلة منقوطة وذلك لأنه تعبير نُريد قيمته على أنها قيمة الدالة المُعادة.
</p>

<p>
	دعنا ننظر إلى مثال آخر:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_38" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> plus_one</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn plus_one</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> i32 </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيطبع تنفيذ الشيفرة البرمجية السابقة <code>The value of x is: 6</code>، إلا أننا سنحصل على خطأ إذا استبدلنا الفاصلة المنقوطة في نهاية السطر <code>x + 1</code> مما يُغيّر السطر من تعبير إلى تعليمة.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_40" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> plus_one</span><span class="pun">(</span><span class="lit">5</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

fn plus_one</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> i32 </span><span class="pun">{</span><span class="pln">
    x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</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_8503_42" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> functions v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/functions)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0308</span><span class="pun">]:</span><span class="pln"> mismatched types
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">7</span><span class="pun">:</span><span class="lit">24</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> fn plus_one</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln"> i32</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> i32 </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"> expected </span><span class="pun">`</span><span class="pln">i32</span><span class="pun">`,</span><span class="pln"> found </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">    implicitly returns </span><span class="pun">`()`</span><span class="pln"> as its body has no tail or </span><span class="pun">`</span><span class="kwd">return</span><span class="pun">`</span><span class="pln"> expression
</span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">          </span><span class="pun">-</span><span class="pln"> help</span><span class="pun">:</span><span class="pln"> remove </span><span class="kwd">this</span><span class="pln"> semicolon

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0308</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">functions</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	تُشير الرسالة الأساسية إلى أن سبب الخطأ هو بسبب "أنواع غير متوافقة mismatched types". يدل تعريف الدالة <code>plus_one</code> على أنها تُعيد قيمةً من النوع <code>i32</code> إلا أن التعبير لا يُقيَّم إلى قيمة، وهو الشيء المُعبّر بالقوسين <code>()</code> نوع الوحدة unit type، وبالتالي لا يوجد هناك أي قيمة لإعادتها مما يتناقض مع تعريف الدالة ويتسبب بخطأ. توفّر راست في رسالة الخطأ رسالةً لمساعدتك في حل هذه المشكلة إذ تقترح إزالة الفاصلة المنقوطة مما سيحلّ المشكلة بدوره.
</p>

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

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

<p>
	إليك تعليقًا بسيطًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_44" style=""><span class="com">// hello, world</span></pre>

<p>
	يبدأ التعليق في لغة راست بشرطتين مائلتين ويستمر التعليق إلى نهاية السطر، وإذا أردت استخدام التعليق ليشمل عدّة أسطر فعليك استخدام <code>//</code> في كل سطر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_46" style=""><span class="com">// So we’re doing something complicated here, long enough that we need</span><span class="pln">
</span><span class="com">// multiple lines of comments to do it! Whew! Hopefully, this comment will</span><span class="pln">
</span><span class="com">// explain what’s going on.</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_48" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let lucky_number </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pun">;</span><span class="pln"> </span><span class="com">// I’m feeling lucky today</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8503_50" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// I’m feeling lucky today</span><span class="pln">
    let lucky_number </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></pre>

<p>
	يوجد طريقة أخرى لكتابة التعليقات ألا وهي التعليقات التوثيقية documentation comments التي سنناقشها لاحقًا.
</p>

<p>
	ترجمة -وبتصرف- للقسم <a href="https://doc.rust-lang.org/stable/book/ch03-03-how-functions-work.html/" rel="external nofollow">Functions</a> والقسم <a href="https://doc.rust-lang.org/stable/book/ch03-04-comments.html/" rel="external nofollow">Comments</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A8%D8%B3%D9%8A%D8%B1-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1785/" rel="">التحكم بسير تنفيذ برامج رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">تعلم لغة رست Rust: البدايات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">برمجة لعبة تخمين الأرقام بلغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1781</guid><pubDate>Wed, 30 Nov 2022 16:09:00 +0000</pubDate></item><item><title>&#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Data Types &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636a4d94e4bac_--Data-Types----Rust.png.39cc6e73c3f6ced027a76da6d44e2653.png" /></p>
<p>
	تنتمي كل قيمة في <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">لغة رست</a> إلى نوع بيانات معيّن، ويُساعد ذلك لغة رست بمعرفة نوع البيانات التي تدلّ عليها هذه القيمة وكيفية التعامل معها، وسننظر إلى مجموعتين من أنواع البيانات، هي: القيم المُفردة scalar والقيم المركّبة compound.
</p>

<p>
	تذكر أن لغة رست لغة برمجة متقيدة ب<a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1726/#%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%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9" rel="">أنواع البيانات</a> statically typed، أي أنه يجب أن تعرف أنواع البيانات جميعها عند وقت التصريف، ويستطيع المصرّف عادةً استنتاج نوع <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات</a> بناءً على القيمة وكيفية استخدامها ضمن الشيفرة البرمجية، إلا أننا يجب أن نحدّد الأنواع في بعض الحالات، مثل التحويل من <code>String</code> إلى نوع عددي باستخدام <code>parse</code> كما رأينا في <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">مقالنا السابق</a> فقرة مقارنة التخمين إلى الرقم السري:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_8" style=""><span class="pln">let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"42"</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Not a number!"</span><span class="pun">);</span></pre>

<p>
	نحصل على الخطأ التالي إن لم نُضف النوع <code>u32 :</code> كما هو موضح أعلاه، ويدل الخطأ على أن المصرّف يحتاج المزيد من المعلومات حول النوع الذي نريد استخدامه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_10" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> no_type_annotations v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/no_type_annotations)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0282</span><span class="pun">]:</span><span class="pln"> type annotations needed
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span><span class="lit">9</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let guess </span><span class="pun">=</span><span class="pln"> </span><span class="str">"42"</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Not a number!"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">         </span><span class="pun">^^^^^</span><span class="pln"> consider giving </span><span class="pun">`</span><span class="pln">guess</span><span class="pun">`</span><span class="pln"> a type

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0282</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">no_type_annotations</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

<p>
	ستجد ترميزًا مختلفًا لكل من أنواع البيانات الأخرى.
</p>

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

<p>
	يمثّل النوع المفرد scalar type قيمة فردية، ولدى لغة رست أربع أنواع مُفردة أولية هي: الأعداد الصحيحة integers والأعداد ذات الفاصلة العشرية floating-point numbers والقيم البوليانية booleans والمحارف characters، وقد تتعرف على بعضها من لغة برمجة أخرى تعاملت معها سابقًا. دعنا نتحدّث عن كيفية استعمال هذه الأنواع في لغة رست.
</p>

<h3>
	أنواع الأعداد الصحيحة
</h3>

<p>
	العدد الصحيح integer هو عدد لا يحتوي على جزء كسري، وسبق لنا استخدام نوع من أنواع الأعداد الصحيحة سابقًا وهو <code>u32</code>، ويحدد التصريح عن هذا النوع أن القيمة المُسندة إلى المتغير ستكون عدد صحيح عديم الإشارة unsigned integer (تبدأ الأعداد الصحيحة ذات الإشارة بالحرف <code>i</code> بدلًا من <code>u</code>)، ويأخذ مساحة 32 بت. يوضّح الجدول 3-1 أنواع الأعداد الصحيحة المُضمّنة في لغة رست، ويمكننا استخدام أي من هذه المتغايرات variants للتصريح عن نوع قيمة العدد الصحيح.
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				الطول
			</th>
			<th>
				ذو إشارة
			</th>
			<th>
				عديم الإشارة
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				8-بت
			</td>
			<td>
				<code>i8</code>
			</td>
			<td>
				<code>u8</code>
			</td>
		</tr>
		<tr>
			<td>
				16-بت
			</td>
			<td>
				<code>i16</code>
			</td>
			<td>
				<code>u16</code>
			</td>
		</tr>
		<tr>
			<td>
				32-بت
			</td>
			<td>
				<code>i32</code>
			</td>
			<td>
				<code>u32</code>
			</td>
		</tr>
		<tr>
			<td>
				64-بت
			</td>
			<td>
				<code>i64</code>
			</td>
			<td>
				<code>u64</code>
			</td>
		</tr>
		<tr>
			<td>
				128-بت
			</td>
			<td>
				<code>i128</code>
			</td>
			<td>
				<code>u128</code>
			</td>
		</tr>
		<tr>
			<td>
				يعتمد على معمارية الحاسب
			</td>
			<td>
				<code>isize</code>
			</td>
			<td>
				<code>usize</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	[جدول 3-1: أنواع الأعداد الصحيحة في راست]
</p>

<p>
	يُمكن أن يكون كل متغاير ذو إشارة أو عديم إشارة وذو طول محدّد، إذ تُشير كلمة ذو إشارة signed وعديم الإشارة unsigned إلى إمكانية كون العدد سالبًا أم لا، وبتعبير آخر، هل يحتاج العدد إلى إشارةٍ معه (ذو إشارة signed) أم أنه سيكون موجبًا فقط وسيُمثّل بالتالي دون أي إشارة (عديم الإشارة unsigned). الأمر مماثل لكتابة الأعداد على ورقة، فعندما نحتاج لاستخدام الإشارة يُوضّح العدد وبجانبه إشارة (سواءً موجبة أو سالبة)، وفي حال كان الافتراض أن جميع الأعداد موجبة، فلا نضع أي إشارة بجانب الأعداد، وتُخزّن الأعداد ذات الإشارة باستخدام تمثيل المتمّم الثنائي two's complement.
</p>

<p>
	يُمكن أن يخزِّن كل متغاير ذي إشارة القيم المنتمية إلى المجال من 2<sup>n-1</sup>- إلى 2<sup>n-1</sup> - 1، إذ تمثّل "n" عدد البتات التي يستخدمها المتغاير، وبالتالي يمكن للنوع <code>i8</code> تخزين القيم التي تنتمي إلى المجال من 2<sup>7</sup>- إلى 1- 2<sup>7</sup> الذي يساوي من ‎-128 إلى 127، بينما يمكن للمتغايرات عديمة الإشارة تخزين القيم ضمن المجال من 0 إلى 2<sup>n</sup>-1، وبالتالي يمكن للنوع <code>u8</code> أن يخزن الأعداد من 0 إلى 2<sup>8</sup>-1 وهو ما يساوي المجال من 0 إلى 255.
</p>

<p>
	إضافةً لما سبق، يعتمد النوعان <code>isize</code> و<code>usize</code> على معمارية الحاسب الذي يعمل عليه برنامجك، وهو بطول 64 بت إذا كان من معمارية 64 بت وبطول 32 بت إذا كان من معمارية 32 بت.
</p>

<p>
	يُمكنك كتابة الأعداد الصحيحة المُجرّدة integer literals بأي من التنسيقات الموضحة في الجدول 3-2، لاحظ أن لغة رست توفر صياغة لكتابة الأعداد بطريقة تدل على نوعها لتمثيل عدة أنواع عددية إذ تسمح بوجود لاحقة للنوع type suffix مثل "57u8" لتحديد نوعه، ويُمكن أن تستخدم صياغة الأعداد تلك أيضًا الرمز <code>_</code> بمثابة فاصل بصري لجعل الأعداد أسهل للقراءة مثل "1‎_000" الذي يحمل القيمة "1000" ذاتها.
</p>

<table>
	<thead>
		<tr>
			<th>
				العدد المجرد
			</th>
			<th>
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				عشري
			</td>
			<td>
				<code>98‎_222</code>
			</td>
		</tr>
		<tr>
			<td>
				ست عشري
			</td>
			<td>
				<code>0xff</code>
			</td>
		</tr>
		<tr>
			<td>
				ثُماني
			</td>
			<td>
				<code>0o77</code>
			</td>
		</tr>
		<tr>
			<td>
				ثُنائي
			</td>
			<td>
				<code>0b1111_0000</code>
			</td>
		</tr>
		<tr>
			<td>
				بايت (فقط بحجم <code>u8</code>)
			</td>
			<td>
				<code>b'A'‎</code>
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	[جدول 3-2: الأعداد الصحيحة المجردة في لغة رست]
</p>

<p>
	إذًا، كيف يمكنك معرفة أي أنواع الأعداد الصحيحة التي يجب عليك استخدامها؟ أنواع لغة رست الافتراضية هي الخيار الأمثل إذا لم تكُن متأكدًا بخصوص هذا الأمر، نوع العدد الصحيح الافتراضي هو <code>i32</code>، والحالة التي قد تستخدم فيها أحد النوعين <code>isize</code> أو<code>usize</code> هي عندما تستخدم قيمة المتغير دليلًا index ما ضمن مجموعة collection.
</p>

<h4>
	طفحان الأعداد الصحيحة
</h4>

<p>
	بفرض أن هناك متغير من النوع <code>u8</code> الذي يمكنه تخزين القيم من 0 إلى 255. إذا حاولت إسناد قيمة إلى ذلك المتغير خارج النطاق المذكور -مثل القيمة 256- فسيتسبب ذلك بحدوث ما يسمى طفحان الأعداد الصحيحة integer overflow الذي قد يتسبب بحدوث نتيجة من اثنتان.
</p>

<p>
	تتفقد لغة رست عند تصريف البرنامج في نمط تنقيح الأخطاء debug mode حالات طفحان الأعداد الصحيحة التي ستتسبب بهلع panic برنامجك عند تشغيله، ويستخدم مبرمجو لغة رست مصطلح <strong>هلع panic</strong> عندما يتوقف البرنامج بسبب خطأ ما، وسنناقش هذا الأمر بتعمق أكبر لاحقًا. لا تتحقق لغة رست من حالات طفحان الأعداد الصحيحة التي تتسبب بهلع البرنامج عند تصريفه باستخدام نمط الإطلاق release mode باستخدام الراية flag‏ <code>‎--release</code>، وتجري راست بدلًا من ذلك عمليةً تُعرف بانتقال المتمم الثنائي two's complement wrapping إذا حدث أي طفحان. باختصار، تنتقل القيمة التي تحتوي على قيمة أكبر من القيمة العظمى الممكن للنوع تخزينها إلى أصغر قيمة يمكن للمتغير تخزينها، فعلى سبيل المثال تصبح القيمة 256 في النوع <code>u8</code> مساويةً إلى الصفر والقيمة 257 إلى 1 وهكذا، لن يهلع البرنامج في هذه الحالة، بل سيحمل المتغير قيمةً مختلفة، ويُعدّ الاعتماد على عملية الانتقال wrapping في طفحان الأعداد الصحيحة خطأً.
</p>

<p>
	يُمكنك استخدام أحد الطرق التالية للتعامل على نحوٍ صريح مع حالات الطفحان وهي طرق مُضمنّة في المكتبة القياسية للأنواع العددية الأولية:
</p>

<ul>
	<li>
		تمكين الانتقال في جميع أنماط بناء البرنامج باستخدام توابع <code>wrapping_*‎</code> مثل <code>wrapping_add</code>.
	</li>
	<li>
		إعادة القيمة <code>None</code> إذا لم يكن هناك أي طفحان باستخدام التوابع <code>checked_*‎</code>.
	</li>
	<li>
		إعادة القيمة والقيمة البوليانية التي تشير إلى حدوث طفحان باستخدام توابع <code>overflowing_*‎</code>.
	</li>
	<li>
		إشباع saturate القيم العُظمى والدُنيا للقيمة باستخدام توابع <code>saturating_*‎</code>.
	</li>
</ul>

<h3>
	أنواع أعداد الفاصلة العشرية
</h3>

<p>
	لدى لغة راست نوعَين من أنواع أعداد الفاصلة العشرية floating-point numbers وهي الأعداد التي تحتوي على فواصل عشرية، وهما <code>f32</code> و <code>f64</code>، وبحجم 32 بت و64 بت، والنوع الافتراضي هو <code>f64</code>، لأنها تكون بنفس سرعة المُعالجات الحديثة <code>f32</code> ولكنها أكثر دقة، وجميع أنواع أعداد الفاصلة العشرية ذات إشارة.
</p>

<p>
	إليك مثالًا يوضح أعداد الفاصلة العشرية عمليًا:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_12" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2.0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// f64</span><span class="pln">

    let y</span><span class="pun">:</span><span class="pln"> f32 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3.0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// f32</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُمثّل أعداد الفاصلة العشرية بحسب معيار IEEE-754. للنوع <code>f32</code> دقة وحيدة single-precision، بينما للنوع <code>f64</code> دقة مضاعفة double precision.
</p>

<h3>
	العمليات على الأنواع العددية
</h3>

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

<p>
	اسم الملف src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_14" style=""><span class="pln">fn 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">
    let sum </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">10</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// الطرح</span><span class="pln">
    let difference </span><span class="pun">=</span><span class="pln"> </span><span class="lit">95.5</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4.3</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// الضرب</span><span class="pln">
    let product </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// القسمة</span><span class="pln">
    let quotient </span><span class="pun">=</span><span class="pln"> </span><span class="lit">56.7</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">32.2</span><span class="pun">;</span><span class="pln">
    let floored </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Results in 0</span><span class="pln">

    </span><span class="com">// باقي القسمة</span><span class="pln">
    let remainder </span><span class="pun">=</span><span class="pln"> </span><span class="lit">43</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<h3>
	النوع البولياني
</h3>

<p>
	للنوع البولياني boolean type في لغة رست -كما هو الحال في معظم لغات البرمجة الأخرى- قيمتان: <code>true</code> و <code>false</code>، ويبلغ حجم النوع هذا بتًا واحدًا، ويُحدّد النوع البولياني في لغة راست باستخدام الكلمة <code>bool</code> كما يوضح المثال التالي:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_16" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let t </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

    let f</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تحديد النوع بوضوح</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الاستخدام الأساسي للقيم البوليانية هو في التعابير الشرطية conditionals مثل تعابير <code>if</code>، وسنغطّي تعابير <code>if</code> وكيفية عملها في لغة رست لاحقًا.
</p>

<h3>
	نوع المحرف
</h3>

<p>
	نوع <code>char</code> في لغة رست هو أكثر أنواع القيم الأبجدية بدائية، إليك بعض الأمثلة عن تصريح قيم <code>char</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_18" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let c </span><span class="pun">=</span><span class="pln"> </span><span class="str">'z'</span><span class="pun">;</span><span class="pln">
    let z</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ℤ'</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تحديد النوع بوضوح</span><span class="pln">
    let heart_eyed_cat </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></pre>

<p>
	لاحظ أننا حددنا النوع <code>char</code> المجرد باستخدام علامتَي تنصيص فردية، بعكس نوع السلسلة النصية string المجرّد الذي يستخدم علامتَي تنصيص مزدوجة، ويبلغ حجم النوع <code>char</code> في لغة راست أربعة بايتات وتمثل القيمة قيمة يونيكود Unicode عددية التي يُمكن أن تمثل قيمًا أكثر ممّا تستطيع الآسكي ASCII تمثيله. تتضمن لغة راست كذلك الأحرف المُعلّمة accented letters وكل من المحارف الصينية واليابانية والكورية، إضافةً إلى الرموز التعبيرية emoji والمسافات الفارغة ذات العرض الصفري zero-width space، إذ تُعد جميع القيم السابقة المذكورة قيمًا صالحة ويُمكن تخزينها في متغير من نوع <code>char</code>.
</p>

<p>
	تتراوح قيم يونيكود العددية من "U+0000" إلى "U+D7FF" ومن "U+E000" إلى "U+10FFFF"، إلا أن مصطلح المحرف character غير موجود في نظام اليونيكود، وبالتالي يمكن ألا يتطابق فهمك كإنسان لماهية المحرف مع تعريف النوع <code>char</code> في لغة راست، وسنناقش هذا الموضوع بالتفصيل لاحقًا.
</p>

<h2>
	الأنواع المركبة
</h2>

<p>
	يُمكن للأنواع المركبة compound types أن تجمع عدّة قيم في نوع واحد، وللغة رست نوعان من الأنواع المركبة وهي المجموعات tuples والمصفوفات arrays.
</p>

<h3>
	نوع المجموعة
</h3>

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

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_20" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let tup</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> f64</span><span class="pun">,</span><span class="pln"> u8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6.4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_22" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let tup </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6.4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">

    let </span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> tup</span><span class="pun">;</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of y is: {y}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُنشئ هذا البرنامج مجموعة ويُسندها إلى المتغير <code>tup</code>، ومن ثم يستخدم نمطًا مع <code>let</code> لأخذ المتغير <code>tup</code> وتحويله إلى ثلاث قيم منفصلة وهي <code>x</code> و <code>y</code> و <code>z</code>، ويدعى هذا بالتفكيك destructuring لأنه يُفكك المجموعة الواحدة إلى ثلاث أجزاء، ويطبع البرنامج أخيرًا قيمة <code>y</code> المساوية إلى "6.4".
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_24" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i32</span><span class="pun">,</span><span class="pln"> f64</span><span class="pun">,</span><span class="pln"> u8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6.4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">

    let five_hundred </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">.</span><span class="lit">0</span><span class="pun">;</span><span class="pln">

    let six_point_four </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">.</span><span class="lit">1</span><span class="pun">;</span><span class="pln">

    let one </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">.</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

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

<p>
	للمجموعة اسم مميّز إذا كانت فارغة ألا وهو <strong>الوحدة unit</strong>، وتُكتب قيمتها وقيمة أنواعها بالشكل <code>()</code>، اللتان تُمثّلان قيمة فارغة أو قيمة إعادة فارغة empty return type، تُعيد التعابير ضمنيًا قيمة الوحدة إذا لم يكن التعبير يُعيد أي قيمة أخرى.
</p>

<h3>
	نوع المصفوفة
</h3>

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

<p>
	نكتب القيم في المصفوفة مثل لائحة من القيم مفصول ما بينها بفاصلة داخل أقواس معقوفة square brackets:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_26" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let a </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_28" style=""><span class="pln">let months </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">"January"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"February"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"March"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"April"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"May"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"June"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"July"</span><span class="pun">,</span><span class="pln">
              </span><span class="str">"August"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"September"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"October"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"November"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"December"</span><span class="pun">];</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_30" style=""><span class="pln">let a</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">i32</span><span class="pun">;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span></pre>

<p>
	يمثل النوع <code>i32</code> في مثالنا هذا نوع عناصر المصفوفة، بينما يمثل العدد "5" الذي يقع بعد الفاصلة المنقوطة عدد عناصر المصفوفة الخمس.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_32" style=""><span class="pln">let a </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">5</span><span class="pun">];</span></pre>

<p>
	ستحتوي المصفوفة <code>a</code> على 5 عناصر وستكون قيم العناصر جميعها مساوية إلى 3 مبدئيًا، وهذا الأمر مماثل لكتابة السطر البرمجي <code>let a = [3, 3, 3 ,3 ,3];‎</code> إلا أن هذه الطريقة مختصرة.
</p>

<h4>
	الوصول إلى عناصر المصفوفة
</h4>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_34" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let a </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

    let first </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
    let second </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في مثالنا السابق، سيُسند إلى المتغير <code>first</code> القيمة الابتدائية 1 لأنها القيمة الموجودة في الدليل <code>[0]</code> ضمن المصفوفة، بينما سيُسند إلى المتغير <code>second</code> القيمة 2 لأنها القيمة الموجودة في الدليل<code>[1]</code> ضمن المصفوفة.
</p>

<h4>
	محاولة الوصول الخاطئ إلى عناصر المصفوفة
</h4>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_36" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let a </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="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">];</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please enter an array index."</span><span class="pun">);</span><span class="pln">

    let mut index </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span><span class="pln">

    io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut index</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

    let index</span><span class="pun">:</span><span class="pln"> usize </span><span class="pun">=</span><span class="pln"> index
        </span><span class="pun">.</span><span class="pln">trim</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">parse</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Index entered was not a number"</span><span class="pun">);</span><span class="pln">

    let element </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">index</span><span class="pun">];</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of the element at index {index} is: {element}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُصرّف الشيفرة البرمجية بنجاح، وإذا شغلت البرنامج باستخدام <code>cargo run</code> وأدخلت القيم 0 أو 1 أو 2 أو 3 أو 4، فسيطبع البرنامج القيمة الموافقة لهذا الدليل ضمن المصفوفة، إلا أنك ستحصل على الخرج التالي إذا حاولت إدخال قيمة أكبر من حجم المصفوفة (مثل 10):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6002_38" style=""><span class="pln">thread </span><span class="str">'main'</span><span class="pln"> panicked at </span><span class="str">'index out of bounds: the len is 5 but the index is 10'</span><span class="pun">,</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">19</span><span class="pun">:</span><span class="lit">19</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> run with </span><span class="pun">`</span><span class="pln">RUST_BACKTRACE</span><span class="pun">=</span><span class="lit">1</span><span class="pun">`</span><span class="pln"> environment variable to display a backtrace</span></pre>

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

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

<p>
	ترجمة -وبتصرف- للقسم <a href="https://doc.rust-lang.org/stable/book/ch03-02-data-types.html/" rel="external nofollow">Data Types</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%84%D9%8A%D9%82%D8%A7%D8%AA-comments-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%A7%D8%B3%D8%AA-rust-r1781/" rel="">كيفية كتابة الدوال Functions والتعليقات Comments في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">تعلم لغة رست Rust: البدايات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">برمجة لعبة تخمين الأرقام بلغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1780</guid><pubDate>Thu, 24 Nov 2022 16:09:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62A;&#x639;&#x62F;&#x64A;&#x644; &#x639;&#x644;&#x64A;&#x647;&#x627; &#x641;&#x64A; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A;</title><link>https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636a4b520521a_-----.png.d1ba6aea6d4e898740501a5e134b446a.png" /></p>
<p>
	المتغيرات في رست غير قابلة للتعديل افتراضيًا كما ذكرنا في السابق، وهذه ميزة من ميزات لغة راست التي تهدف إلى جعل شيفرتك البرمجية المكتوبة آمنة وسهلة التزامن concurrency قدر الإمكان، إلا أنها تمنحك خيار التعديل mutable على المتغيرات إذا أردت ذلك. دعنا نرى لماذا تفضّل لغة راست جعل المتغيرات غير قابلة للتعديل في المقام الأول وما هي الحالات التي قد تريد التعديل عليها.
</p>

<h2>
	قابلية التعديل على المتغيرات
</h2>

<p>
	عندما تُسند أي قيمة إلى اسم متغيرٍ ما للمرة الأولى فهي غير قابلة للتغيير. لتوضيح ذلك دعنا نولّد مشروعًا جديدًا باسم "variables" في مجلد "projects" باستخدام الأمر <code>cargo new variables</code>.
</p>

<p>
	بعد ذلك، افتح افتح الملف "src/main.rs" في المجلد "variables" الجديد، واستبدل الشيفرة البرمجية الموجودة داخله بالشيفرة التالية. لن تُصرّف الشيفرة البرمجية هذه بعد، وسنفحص أولًا خطأ عدم قابلية التعديل immutability error.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_7" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ وشغّل البرنامج باستخدام الأمر <code>cargo run</code>، إذ يجب أن تتلقى رسالة خطأ كما هو موضّح في الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_9" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> variables v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/variables)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0384</span><span class="pun">]:</span><span class="pln"> cannot assign twice to immutable variable </span><span class="pun">`</span><span class="pln">x</span><span class="pun">`</span><span class="pln">
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">4</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">         </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">         first assignment to </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">         help</span><span class="pun">:</span><span class="pln"> consider making </span><span class="kwd">this</span><span class="pln"> binding </span><span class="kwd">mutable</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">mut x</span><span class="pun">`</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">     </span><span class="pun">^^^^^</span><span class="pln"> cannot assign twice to immutable variable

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0384</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">variables</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<p>
	تُشير رسالة الخطأ "<code>cannot assign twice immutable variable</code>x" إلى أنك لا تستطيع إعادة إسناد قيمة أخرى إلى المتغير غير القابل للتعديل <code>x</code>.
</p>

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

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

<p>
	على سبيل المثال، دعنا نغير محتويات الملف "src/main.rs" إلى التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_11" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
    x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pun">;</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</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_4803_13" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> variables v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/variables)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.30s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">variables</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span></pre>

<p>
	سُمح لنا الآن بتغيير قيمة <code>x</code> من 5 إلى 6 عند استخدام <code>mut</code>. يعتمد استخدام -أو عدم استخدام- قابلية التعديل على الشيء الأكثر وضوحًا في كل حالة بنظرك.
</p>

<h2>
	الثوابت
</h2>

<p>
	الثوابت constants هي قيم مُسندة إلى اسم ما ولا يُمكن تغييرها كما هو الحال في المتغيرات غير القابلة للتعديل، إلا أن هناك بعض الفروقات بين الثوابت والمتغيرات.
</p>

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

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

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

<p>
	إليك مثالًا عن تصريح ثابت ما:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_15" style=""><span class="kwd">const</span><span class="pln"> THREE_HOURS_IN_SECONDS</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">60</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">60</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span></pre>

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

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

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

<h2>
	التظليل
</h2>

<p>
	يُمكنك التصريح عن متغير جديد يحمل اسمًا مماثلًا لمتغير آخر سابق كما رأينا في <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">المقال السابق</a> الذي ناقش كيفية برمجة لعبة تخمين، ويقول مبرمجو اللغة عادةً أن المتغير الأوّل تظلّل shadowed بالثاني، مما يعني أن المتغير الثاني هو ما سيجده المُصرّف عندما تستخدم اسم المتغير من النقطة تلك فصاعدًا. بالمثل، فالمتغير الثاني ظَلّل overshadow الأول آخذًا استخدامات اسم المتغير لنفسه حتى يُظلّل المتغير الثاني بنفسه أو ينتهي النطاق الذي ينتمي إليه. يمكننا تظليل متغير ما باستخدام اسم المتغير ذاته وإعادة استخدامه مع الكلمة المفتاحية <code>let</code> كما هو موضح:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_19" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

    let x </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

    </span><span class="pun">{</span><span class="pln">
        let x </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="pun">;</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"The value of x in the inner scope is: {x}"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The value of x is: {x}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُسند البرنامج أولًا المتغير <code>x</code> إلى القيمة 5، ثم يُنشئ متغيرًا جديدًا <code>x</code> بتكرار <code>let x =‎</code> آخذًا القيمة الأصلية ومُضيفًا إليها 1، وبالتالي تصبح قيمة <code>x</code> مساويةً إلى 6، ثم تُظلّل تعليمة <code>let</code> الثالثة ضمن النطاق الداخلي المحتوى داخل الأقواس المعقوصة curly brackets المتغير <code>x</code> وتنشئ متغير <code>x</code> مجددًا وتضرب قيمته السابقة بالرقم 2، فتصبح قيمة المتغير 12، وعند نهاية النطاق ينتهي التظليل الداخلي ويعود المتغير <code>x</code> إلى قيمته السابقة 6. نحصل على الخرج التالي عند تشغيل البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_21" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> variables v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/variables)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.31s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">variables</span><span class="pun">`</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x in the inner scope is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> value of x is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span></pre>

<p>
	التظليل مختلف عن استخدام الكلمة المفتاحية <code>mut</code> لأنك ستحصل على خطأ تصريفي compile-time error إذا حاولت إعادة إسناد قيمة إلى هذا المتغير عن طريق الخطأ دون استخدام الكلمة المفتاحية <code>let</code>. يمكننا إجراء عدة تغييرات على قيمة ما باستخدام <code>let</code> وجعل المتغير غير قابل للتعديل بعد هذه استكمال هذه التغييرات.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_23" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let spaces </span><span class="pun">=</span><span class="pln"> </span><span class="str">"   "</span><span class="pun">;</span><span class="pln">
    let spaces </span><span class="pun">=</span><span class="pln"> spaces</span><span class="pun">.</span><span class="pln">len</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	متغير <code>spaces</code> الأول من نوع سلسلة نصية string بينما المتغير <code>spaces</code> الآخر من نوع عددي، إذًا، يوفّر علينا التظليل هنا عناء إنشاء متغير باسم جديد، مثل <code>spaces_str</code> و <code>spaces_num</code>، ويمكننا بدلًا من ذلك إعادة استخدام الاسم "spaces"، إلا أننا سنحصل على خطأ تصريفي إذا حاولنا استخدام <code>mut</code> في هذه الحالة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4803_25" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let mut spaces </span><span class="pun">=</span><span class="pln"> </span><span class="str">"   "</span><span class="pun">;</span><span class="pln">
    spaces </span><span class="pun">=</span><span class="pln"> spaces</span><span class="pun">.</span><span class="pln">len</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_4803_27" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> variables v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/variables)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0308</span><span class="pun">]:</span><span class="pln"> mismatched types
 </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">3</span><span class="pun">:</span><span class="lit">14</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     let mut spaces </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">                      </span><span class="pun">-----</span><span class="pln"> expected due to </span><span class="kwd">this</span><span class="pln"> value
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     spaces </span><span class="pun">=</span><span class="pln"> spaces</span><span class="pun">.</span><span class="pln">len</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">|</span><span class="pln">              </span><span class="pun">^^^^^^^^^^^^</span><span class="pln"> expected </span><span class="pun">`&amp;</span><span class="pln">str</span><span class="pun">`,</span><span class="pln"> found </span><span class="pun">`</span><span class="pln">usize</span><span class="pun">`</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about </span><span class="kwd">this</span><span class="pln"> error</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">`</span><span class="pln">rustc </span><span class="pun">--</span><span class="pln">explain E0308</span><span class="pun">`.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could not compile </span><span class="pun">`</span><span class="pln">variables</span><span class="pun">`</span><span class="pln"> due to previous error</span></pre>

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

<p>
	ترجمة -وبتصرف- للقسم <a href="https://doc.rust-lang.org/stable/book/ch03-01-variables-and-mutability.html/" rel="external nofollow">Variables and Mutability</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%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-data-types-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1780/" rel="">أنواع البيانات Data Types في لغة رست Rust</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">برمجة لعبة تخمين الأرقام بلغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">برمجة لعبة تخمين الأرقام بلغة رست Rust</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1779</guid><pubDate>Thu, 17 Nov 2022 16:08:00 +0000</pubDate></item><item><title>&#x628;&#x631;&#x645;&#x62C;&#x629; &#x644;&#x639;&#x628;&#x629; &#x62A;&#x62E;&#x645;&#x64A;&#x646; &#x627;&#x644;&#x623;&#x631;&#x642;&#x627;&#x645; &#x628;&#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust</title><link>https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/6363984f6725f_------Rust.png.df7a8ff497118418852b9cf8deffc3c8.png" /></p>
<p>
	دعنا نتعرّف إلى <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">رست</a> بالعمل على مشروع عملي سويًّا، إذ سيقدم هذا المقال بعض المفاهيم الشائعة في رست وكيفية استخدامها في برامج حقيقية، وسنتعلم كل من <code>let</code> و <code>match</code> والتوابع methods والدوال المترابطة associated functions واستخدام صناديق crates خارجية والمزيد، وسنناقش هذه التفاصيل بتعمق أكبر في مقالات لاحقة، إلا أننا سنتدرب على الأساسيات في هذا المقال.
</p>

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

<h2>
	إعداد المشروع الجديد
</h2>

<p>
	اذهب إلى مجلد "directory" الذي أنشأناه في <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">المقال السابق</a> لإعداد المشروع الجديد باستخدام أداة كارجو Cargo كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_8" style=""><span class="pln">$ cargo </span><span class="kwd">new</span><span class="pln"> guessing_game
$ cd guessing_game</span></pre>

<p>
	يأخذ الأمر الأول <code>cargo new</code> اسم المشروع، وهو في حالتنا "guessing_game" مقل وسيطٍ أول، بينما ينتقل الأمر الثاني إلى مجلد المشروع.
</p>

<p>
	ألقِ نظرةً إلى محتويات الملف "Cargo.toml" الناتج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_10" style=""><span class="pun">[</span><span class="pln">package</span><span class="pun">]</span><span class="pln">
name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"guessing_game"</span><span class="pln">
version </span><span class="pun">=</span><span class="pln"> </span><span class="str">"0.1.0"</span><span class="pln">
edition </span><span class="pun">=</span><span class="pln"> </span><span class="str">"2021"</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"> https</span><span class="pun">:</span><span class="com">//doc.rust-lang.org/cargo/reference/manifest.html</span><span class="pln">

</span><span class="pun">[</span><span class="pln">dependencies</span><span class="pun">]</span></pre>

<p>
	كما رأينا في المقال السابق، يولّد الأمر <code>cargo new</code> برنامج "!Hello, world" لك. ألقِ نظرةً على محتويات ملف "src/main.rs":
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_22" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Hello, world!"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	دعنا الآن نصرّف هذا البرنامج ونشغله باتباع نفس الخطوة وباستخدام أمر <code>cargo run</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_24" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">1.50s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="str">`target/debug/guessing_game`</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

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

<p>
	أعِد الآن فتح الملف "src/main.rs"، إذ سنكتب الشيفرة البرمجية لمشروعنا فيه.
</p>

<h2>
	معالجة التخمين
</h2>

<p>
	الجزء الأول من برنامج لعبة التخمين هو سؤال المستخدم ليدخل التخمين، ومن ثم معالجة هذا الدخل والتحقق من أنه بتنسيق مناسب. دعنا بدايةً نسمح المستخدم بإدخال تخمين. اكتب الشيفرة التالية في الملف "src/main.rs":
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_20" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

    let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

    io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[شيفرة 2-1: شيفرة برمجية تأخذ التخمين من المستخدم في الدخل وتطبعه]
</p>

<p>
	تحتوي الشيفرة البرمجية السابقة على كثيرٍ من المعلومات الجديدة، لذلك دعنا نراجعها سطرًا بسطر. علينا أن نستخدم المكتبة <code>io</code> وأن نضيفها إلى نطاق scope المشروع للحصول على دخل المستخدم ومن ثم طباعة نتيجة الدخل في الخرج؛ إذ تأتي مكتبة <code>io</code> مع المكتبة القياسية، التي تُعرف باسم <code>std</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_26" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span></pre>

<p>
	تحتوي رست افتراضيًا على مجموعةٍ معرفةٍ من العناصر ضمن المكتبة القياسية التي تُضاف إلى نطاق أي برنامج، وتُسمى هذه العناصر باسم المقدمة prelude ويمكنك رؤية جميع محتوياتها في <a href="https://doc.rust-lang.org/stable/std/prelude/index.html" rel="external nofollow">توثيق المكتبة القياسية</a>.
</p>

<p>
	إذا أردت استخدام نوع محدد غير متواجد في المقدمة، فعليك إضافته إلى النطاق عن طريق استخدام تعليمة <code>use</code>. تتيح لك مكتبة <code>std::io</code> استخدام عدد من المزايا المفيدة منها القدرة على تلقّي دخل المستخدم.
</p>

<p>
	دالة <code>main</code> هي النقطة التي يبدأ منها البرنامج كما رأينا في المقال السابق:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_28" style=""><span class="pln">fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	تصرّح الصيغة <code>fn</code> عن دالة جديدة وتُشير الأقواس <code>()</code> إلى أن الدالة لا تأخذ أي معاملات، ويُشير القوس المعقوص <code>}</code> إلى بداية متن الدالة.
</p>

<p>
	تشير <code>println!‎</code> إلى ماكرو كما تطرقنا إلى ذلك في المقال السابق ويطبع هذا الماكرو السلسلة النصية إلى الشاشة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_38" style=""><span class="pln">    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span></pre>

<p>
	تطبع الشيفرة السابقة جملةً تدلّ المستخدم على ماهية اللعبة ومن ثم جملة تطلب منه إدخالًا.
</p>

<h2>
	تخزين القيم والمتغيرات
</h2>

<p>
	نُنشئ الآن متغيرًا لتخزين دخل المستخدم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_36" style=""><span class="pln">let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="kwd">new</span><span class="pun">();</span></pre>

<p>
	أصبح الآن برنامجنا أكثر إثارةً للاهتمام؛ فهناك الكثير من الأشياء التي تحدث عند تنفيذ هذا السطر القصير، إذ نستخدم تعليمة <code>let</code> لإنشاء متغير، إليك مثالًا آخر عن إنشاء متغير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_40" style=""><span class="pln">let apples </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span></pre>

<p>
	يُنشئ هذا السطر متغيرًا جديدًا باسم apples ويُسنده إليه القيمة 5. المتغيرات في لغة رست ثابتة immutable افتراضيًا، وهذا يعني أن المتغير سيحافظ على قيمته الأولية التي أُسندت إليه ولن تُغيّر وسنتحدث في هذا الموضوع بتوسع أكثر لاحقًا. لجعل المتغير قابلًا للتغيير mutable نستخدم الكلمة المفتاحية <code>mut</code> قبل اسم المتغير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_42" style=""><span class="pln">let apples </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ثابت</span><span class="pln">
let mut bananas </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="com">// متغيّر</span></pre>

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

<p>
	بالعودة إلى برنامج لعبة التخمين، فأنت تعلم الآن أن <code>let mut guess</code> سيُضيف متغيرًا يقبل التغيير باسم guess، وتُخبر إشارة المساواة <code>=</code> رست أنّنا نريد إسناد قيمة ما إلى المتغير، يقع على يمين إشارة المساواة القيمة التي نريد إسنادها إلى <code>guess</code> وهي قيمةٌ ناتجةٌ عن استدعاء الدالة <code>String::new</code> وهي دالة تُعيد نُسخةً instance من النوع "String"؛ وهو نوع من أنواع السلاسل النصية الموجود في المكتبة القياسية وهو نص بترميز UTF-8 وقابل للزيادة.
</p>

<p>
	تُشير <code>::</code> في السطر <code>new::</code> إلى أن <code>new</code> مرتبطةٌ بدالة من نوع String؛ و<strong>الدالة المرتبطة associated function</strong> هي دالة تُطبّق على نوع ما -وفي هذه الحالة هو String- وتُنشئ الدالة <code>new</code> هذه سلسلةً نصيةً جديدةً وفارغة، وستجد دالة <code>new</code> هذه في العديد من الأنواع لأنه اسم شائع لدالة تُنشئ قيمةً جديدةً من نوعٍ ما.
</p>

<p>
	إذا نظرنا إلى السطر <code>let mut guess = String::new();‎</code> كاملًا، فهو سطرٌ لإنشاء متغير قابل للتغيير مُسندٌ إلى نُسخة جديدة وفارغة من النوع String.
</p>

<h2>
	تلقي دخل المستخدم
</h2>

<p>
	تذكر أننا ضمّننا إمكانية تلقي الدخل وعرض الخرج عن طريق <code>use std::io;‎</code> من المكتبة القياسية في السطر الأول من البرنامج. دعنا الآن نستدعي دالة <code>stdin</code> من وحدة <code>io</code> التي ستسمح لنا بالتعامل مع دخل المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_46" style=""><span class="pln">io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span></pre>

<p>
	يمكننا استخدام استدعاء الدالة السابقة حتى لو لم نستورد مكتبة <code>io</code> بكتابتنا <code>use std::io</code> في بداية البرنامج ولكن الاستدعاء حينها سيكون بالشكل <code>std::io::stdin</code>. تُعيد الدالة <code>stdin</code> نسخة من النوع <code>std::io::Stdin</code> وهو نوع يُمثّل مُعالجًا للدخل القياسي من الطرفية.
</p>

<p>
	يستدعي السطر <code>‎.read_line(&amp;mut guess)‎</code> تابع <code>read_line</code> ضمن معالج الدخل القياسي للحصول على دخل المستخدم، كما أننا نمرّر <code>‎&amp;mut guess</code> مثل وسيط إلى <code>read_line</code> للدلالة على السلسلة النصية التي سيُخزّن بها دخل المستخدم. تتمثّل وظيفة <code>read_line</code> بأخذ ما يكتبه المستخدم إلى الدخل القياسي وإلحاقه append بالسلسلة النصية (دون الكتابة فوق overwriting محتوياته)، ولذا فنحن نمرّر هنا السلسلة النصية وسيطًا، ويجب أن يكون الوسيط قابلًا للتغيير حتى يكون التابع قادرًا على تغيير محتويات السلسلة النصية.
</p>

<p>
	يُشير الرمز <code>&amp;</code> إلى أن هذا الوسيط يمثل مرجعًا، وهي طريقةٌ تسمح لأجزاء مختلفة من شيفرتك البرمجية بالوصول إلى الجزء ذاته من البيانات دون الحاجة إلى نسخ البيانات إلى الذاكرة عدة مرات. تُعد ميزة المراجع ميزةً معقّدةً وأكبر ميزات رست هو مستوى الأمان العالي وسهولة استخدام المراجع. لا تحتاج لمعرفة المزيد من هذه التفاصيل حتى تُنهي كتابة هذا البرنامج، إذ يكفي للآن أن تعرف أن المراجع غير قابلة للتغيير افتراضيًا -كما هو الحال في المتغيرات- وبالتالي يجب عليك كتابة <code>‎&amp;mut guess</code> بدلًا من <code>‎&amp;guess</code> إذا أردت جعلها قابلة للتغيير (سنشرح لاحقًا المراجع باستفاضة).
</p>

<h3>
	التعامل مع الأخطاء الممكنة باستخدام نوع النتيجة Result
</h3>

<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> ذاته، ونناقش الآن السطر الثالث من النص، إلا أنه يجب الملاحظة أنه يمثل جزءًا من السطر البرمجي المنطقي ذاته. يمثل الجزء الثالث التابع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_49" style=""><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span></pre>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_51" style=""><span class="pln">io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">().</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">).</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span></pre>

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

<p>
	تضع الدالة <code>read_line</code> كل ما يكتبه المستخدم إلى السلسلة النصية التي نمررها لها كما ذكرنا سابقًا، إلا أنها تُعيد أيضًا قيمة <code>Result</code> وهي مُعدّد enumeration وغالبًا ما يُختصر بكتابة enum؛ وهو نوع يُمكن أن يأخذ عدّة حالات ونسمّي كل حالة ممكنة له بمتغاير variant.
</p>

<p>
	سنغطّي المعددات بتفصيل أكبر لاحقًا، إلا أن الهدف من أنواع <code>Result</code> هو لترميز معلومات التعامل مع الأخطاء.
</p>

<p>
	متغايرات <code>Result</code> هي <code>Ok</code> و <code>Err</code>؛ إذ يشير مغاير <code>Ok</code> إلى نجاح العملية ويحتوي بداخله على قيمة النجاح المولّدة؛ بينما يشير المتغاير <code>Err</code> إلى فشل العملية ويحتوي بداخله على معلومات حول سبب أو كيفية فشلها.
</p>

<p>
	لقيم النوع <code>Result</code> توابع معرفة لهم مثل أي قيم من نوع أخر، وتحتوي نسخةُ من النوع <code>Result</code> على التابع <code>expect</code> الذي يمكنك استدعاءه؛ فإذا كانت نسخة <code>Result</code> هذه لها قيمة <code>Err</code> فهذا يعني أن التابع <code>expect</code> سيتسبب بتوقف البرنامج وعرض الرسالة التي مرّرتها وسيطًا إلى التابع <code>expect</code>؛ وإذا أعاد التابع <code>read_line</code> قيمة <code>Err</code>، فهذا يعني أن الخطأ الناجم مرتبط بنظام التشغيل؛ وإذا كانت نسخة <code>Result</code> تحتوي على القيمة <code>Ok</code>، فسيأخذ التابع <code>expect</code> القيمة المُعادة التي تخزنها <code>Ok</code> ويُعيد القيمة إليك فقط كي تستخدمها، وتمثل القيمة في هذه الحالة عدد البايتات التي أدخلها المستخدم.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_53" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/guessing_game)</span><span class="pln">
warning</span><span class="pun">:</span><span class="pln"> unused </span><span class="pun">`</span><span class="typ">Result</span><span class="pun">`</span><span class="pln"> that must be used
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">10</span><span class="pun">:</span><span class="lit">5</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">10</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">().</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</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"> note</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`#[</span><span class="pln">warn</span><span class="pun">(</span><span class="pln">unused_must_use</span><span class="pun">)]`</span><span class="pln"> on by </span><span class="kwd">default</span><span class="pln">
   </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Result</span><span class="pun">`</span><span class="pln"> may be an </span><span class="pun">`</span><span class="typ">Err</span><span class="pun">`</span><span class="pln"> variant</span><span class="pun">,</span><span class="pln"> which should be handled

warning</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">guessing_game</span><span class="pun">`</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bin </span><span class="str">"guessing_game"</span><span class="pun">)</span><span class="pln"> generated </span><span class="lit">1</span><span class="pln"> warning
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.59s</span></pre>

<p>
	يحذرك رست هنا أنك لم تستخدم قيمة <code>Result</code> المُعادة من التابع <code>read_line</code>، مما يعني أن البرنامج لن يستطيع التعامل مع الأخطاء ممكنة الحدوث.
</p>

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

<h3>
	طباعة القيم باستخدام مواضع println!‎ المؤقتة
</h3>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_55" style=""><span class="pln">println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span></pre>

<p>
	يطبع هذا السطر السلسلة النصية التي تحتوي دخل المستخدم، وتمثل مجموعة الأقواس المعقوصة <code>{}</code> مواضع مؤقتة placeholders. فكّر بالأمر وكأن <code>{}</code> كماشة سلطعون تُمسك القيمة في مكانها، ويمكنك طباعة أكثر من قيمة واحدة باستخدام الأقواس المعقوصة، إذ يدل أول قوسين على أول قيمة موجودة في لائحة بعد السلسلة النصية المُنسقّة، ويدل ثاني قوسين على القيمة الثاني في اللائحة وهلم جرًّا. إذا أردنا طباعة عدة قيم باستخدام استدعاء واحد للماكرو <code>println!‎</code> فسيبدو على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_57" style=""><span class="pln">let x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">

println</span><span class="pun">!(</span><span class="str">"x = {} and y = {}"</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span></pre>

<p>
	سنحصل بعد تنفيذ الشيفرة السابقة على الخرج <code>x = 5 and y = 10</code>.
</p>

<h3>
	التأكد من عمل الجزء الأول
</h3>

<p>
	دعنا نتأكد من عمل الجزء الأول من لعبة التخمين، لذلك شغّل الشيفرة البرمجية باستخدام الأمر <code>cargo run</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_59" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/guessing_game)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">6.44s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">guessing_game</span><span class="pun">`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">6</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span></pre>

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

<h2>
	توليد الرقم السري
</h2>

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

<h3>
	استخدام صندوق ما للحصول على إمكانيات أكبر
</h3>

<p>
	تذكر أن الصندوق هو مجموعة من ملفات رست المصدرية، إذ يمثّل المشروع الذي نبنيه الآن صندوقًا ثنائيًا binary crate أي أنه ملف تنفيذي، بينما يمثل صندوق <code>rand</code> صندوق مكتبة library crate، أي أنه يحتوي شيفرة مصدرية مكتوبة لتُستخدم في برامج أخرى ولا يمكن تشغيلها بصورةٍ مستقلة.
</p>

<p>
	تبرز أداة كارجو عند تنسيقها للصناديق الخارجية. قبل كتابة الشيفرة البرمجية التي تستخدم <code>rand</code>، علينا تعديل الملف "Cargo.toml" لتضمين صندوق <code>rand</code> مثل اعتمادية. افتح الملف وأضِف السطر التالي إلى نهاية الملف أسفل ترويسة القسم <code>[dependencies]</code> التي أنشأه لك كارجو مسبقًا، وتأكد من تحديد <code>rand</code> بدقة باستخدام رقم الإصدار وإلا فإن الشيفرة البرمجية الموجودة في المقال قد لا تعمل.
</p>

<p>
	اسم الملف: Cargo.toml
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_61" style=""><span class="pln">rand </span><span class="pun">=</span><span class="pln"> </span><span class="str">"0.8.3"</span></pre>

<p>
	كُل ما يتبع ترويسة القسم في ملف "Cargo.toml" هو جزءٌ من قسم ما يستمر حتى بداية القسم الآخر، وفي القسم <code>[dependencies]</code> أنت تُعلم كارجو بالصناديق الخارجية التي يعتمد مشروعك عليها وأي إصدار منها يتطلّب، ونحدّد في حالتنا هذه الصندوق <code>rand</code> ذو الإصدار "0.8.3"، ويفهم كارجو الإدارة الدلالية لنسخ البرمجيات Semantic Versioning -أو اختصارًا SemVer- وهي صيغة قياسية لكتابة أرقام الإصدارات، وفي الحقيقة فإن الرقم "0.8.3" هو اختصارٌ للرقم "‎^0.8.3"، وهو يعني أن أي إصدار مسموح هو "0.8.3" على الأقل و"0.9.0" على الأكثر.
</p>

<p>
	يضع كارجو في الحسبان أن هذه الإصدارات تحتوي على واجهات برمجية عامة public APIs متوافقة مع الإصدار "0.8.3" ويضمن ذلك التحديد أنك ستحصل على آخر الإصدارات المتوافقة مع الشيفرة البرمجية في هذا المقال، إذ من غير المضمون أن تكون الإصدارات المساوية إلى "0.9.0" أو أعلى تحتوي على ذات الواجهة البرمجية التي نتبعها في الأمثلة هنا.
</p>

<p>
	الآن ومن دون تغيير في الشيفرة البرمجية، دعنا نبني المشروع كما هو موضح في الشيفرة 2-2.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_63" style=""><span class="pln">$ cargo build
    </span><span class="typ">Updating</span><span class="pln"> crates</span><span class="pun">.</span><span class="pln">io index
  </span><span class="typ">Downloaded</span><span class="pln"> rand v0</span><span class="pun">.</span><span class="lit">8.3</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> libc v0</span><span class="pun">.</span><span class="lit">2.86</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> getrandom v0</span><span class="pun">.</span><span class="lit">2.2</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> cfg</span><span class="pun">-</span><span class="kwd">if</span><span class="pln"> v1</span><span class="pun">.</span><span class="lit">0.0</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> ppv</span><span class="pun">-</span><span class="pln">lite86 v0</span><span class="pun">.</span><span class="lit">2.10</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> rand_chacha v0</span><span class="pun">.</span><span class="lit">3.0</span><span class="pln">
  </span><span class="typ">Downloaded</span><span class="pln"> rand_core v0</span><span class="pun">.</span><span class="lit">6.2</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand_core v0</span><span class="pun">.</span><span class="lit">6.2</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> libc v0</span><span class="pun">.</span><span class="lit">2.86</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> getrandom v0</span><span class="pun">.</span><span class="lit">2.2</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> cfg</span><span class="pun">-</span><span class="kwd">if</span><span class="pln"> v1</span><span class="pun">.</span><span class="lit">0.0</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> ppv</span><span class="pun">-</span><span class="pln">lite86 v0</span><span class="pun">.</span><span class="lit">2.10</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand_chacha v0</span><span class="pun">.</span><span class="lit">3.0</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand v0</span><span class="pun">.</span><span class="lit">8.3</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/guessing_game)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">2.53s</span></pre>

<p style="text-align: center;">
	[شيفرة 2-2: الخرج الناتج من تنفيذ الأمر <code>cargo build</code> بعد إضافة صندوق rand مثل اعتمادية]
</p>

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

<p>
	يبحث كارجو عن آخر الإصدارات التي تحتاجها اعتمادية خارجية عند تضمينها وذلك من المسجل registry وهي نسخة من البيانات من <a href="https://crates.io/" rel="external nofollow">Crates.io</a>، وهو موقع ينشر فيه الناس مشاريع رست مفتوحة المصدر حتى يتسنى للآخرين استخدامها.
</p>

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

<p>
	إذا نفذت الأمر <code>cargo build</code> مجددًا دون أي تغيير فلن تحصل على أي خرج إضافي عن السطر <code>Finished</code>، إذ يعرف كارجو أنه حمّل وصرّف الاعتماديات وأنك لم تغيّر أي شيء بخصوصهم في ملف "Cargo.toml"، كما يعرف كارجو أنك لم تغيّر أي شيء على شيفرتك البرمجية ولهذا فهو لا يُعيد تصريفها أيضًا، وفي هذه الحالة لا يوجد أي شيء ليفعله ويغادر مباشرةً.
</p>

<p>
	إذا فتحت الملف "src/main.rs" وعدّلت تعديلًا بسيطًا ومن ثمّ حفظته وحاولت إعادة بناء المشروع، فستجد السطرين التاليين فقط في الخرج:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_65" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">2.53</span><span class="pln"> secs</span></pre>

<p>
	توضح السطور السابقة أن كارجو حدّث وبنى التغييرات الطفيفة إلى الملف "src/main.rs"، ويعلم كارجو أنه يستطيع إعادة استخدام الاعتماديات التي حمّلها سابقًا وصرّفها بما أنك لم تعدل عليها.
</p>

<h3>
	التأكد من أن المشاريع يمكن إعادة إنتاجها باستخدام ملف Cargo.lock
</h3>

<p>
	لدى كارجو آلية تتحقق من أنك تستطيع إعادة بناء الأداة كل مرة تبني أنت أو شخص آخر شيفرتك البرمجية، يستخدم كارجو فقط إصدارات الاعتماديات التي حددتها إلا إذا حددت عكس ذلك. على سبيل المثال، لنقل أن إصدار 0.8.4 من صندوق <code>rand</code> سيُطلق الأسبوع القادم، ويتضمن هذا الإصدار تصحيحًا مهمًا لمشكلة ما إلا أنه يحتوي أيضًا على تراجع regression، وسيتسبب هذا بتعطل شيفرتك البرمجية؛ تُنشئ رست في هذه الحالة ملفًا يدعى "Cargo.lock" عند أول تنفيذ للأمر <code>cargo build</code> ويقع هذا الملف في مجلد "guessing_game".
</p>

<p>
	يوجِد كارجو جميع إصدارات الاعتماديات التي تلائم مشروعك عندما تبنيه للمرة الأولى، ومن ثم يكتب الإصدارات إلى ملف "Cargo.lock"، وبالتالي سيجد كارجو عندما تبني مشروعك في المستقبل أن الملف "Cargo.lock" موجود وسيستخدم عندها الإصدارات المحددة في ذلك الملف بدلًا من إيجاد الإصدارات المناسبة مجددًا، ويسمح لك هذا بالحصول على نسخة من المشروع قابلة لإعادة الإنتاج تلقائيًا، وبكلمات أخرى، سيظلّ مشروعك معتمدًا على الإصدار "0.8.3" حتى تقرّر التحديث إلى إصدار آخر بصورةٍ صريحة، ويعود الشكر إلى ملف "Cargo.lock" في ذلك. بما أن ملف "Cargo.lock" مهم للحصول على نسخ قابلة لإعادة الإنتاج، فمن الشائع أن يُضاف إلى نظام التحكم بالإصدارات version control مع باقي الشيفرة المصدرية في مشروعك.
</p>

<h3>
	تحديث صندوق للحصول على إصدار جديد
</h3>

<p>
	يقدم لك كارجو إمكانية تحديث صندوق ما باستخدام الأمر <code>update</code>، الذي سيتجاهل بدوره الملف "Cargo.lock" وسيبحث عن آخر الإصدارات التي تلائم متطلباتك في ملف "Cargo.toml"، إذ يكتب كارجو هذه الإصدارات إلى "Cargo.lock"، وإلا فسيبحث كارجو افتراضيًا عن إصدارات أحدث من "0.8.3" وأقدم من "0.9.0". إذا كان للصندوق <code>rand</code> إصداران جديدان هما "0.8.4" و"0.9.0" فستجد ما يلي عند تشغيل <code>cargo update</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_69" style=""><span class="pln">$ cargo update
    </span><span class="typ">Updating</span><span class="pln"> crates</span><span class="pun">.</span><span class="pln">io index
    </span><span class="typ">Updating</span><span class="pln"> rand v0</span><span class="pun">.</span><span class="lit">8.3</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> v0</span><span class="pun">.</span><span class="lit">8.4</span></pre>

<p>
	يتجاهل كارجو الإصدار "0.9.0"، وستلاحظ أيضًا بحلول هذه النقطة أن ملف "Cargo.lock" يُشير إلى أن الإصدار الحالي من صندوق <code>rand</code> هو "0.8.4"؛ ولاستخدام الإصدار "0.9.0" من <code>rand</code> أو أي إصدار آخر من السلسلة "x.‏0.9"K عليك تحديث ملف "Cargo.toml" ليبدو على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_71" style=""><span class="pun">[</span><span class="pln">dependencies</span><span class="pun">]</span><span class="pln">
rand </span><span class="pun">=</span><span class="pln"> </span><span class="str">"0.9.0"</span></pre>

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

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

<h2>
	توليد الرقم العشوائي
</h2>

<p>
	دعنا نبدأ باستخدام <code>rand</code> لتوليد الرقم العشوائي، إذ تكمن خطوتنا التالية في التعديل على محتويات الملف "src/main.rs" كما هو موضح في الشيفرة 2-3.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_73" style=""><span class="pln">use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">
use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

    let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

    io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[شيفرة 2-3: إضافة شيفرة برمجية لتوليد الرقم العشوائي]
</p>

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

<p>
	ثم نُضيف سطرين في وسط البرنامج، إذ نستدعي في السطر الأول الدالة <code>rand::thread_rng</code> التي تُعطينا مولّد رقم عشوائي معيّن سنستخدمه وهو مولد محلي لخيط التنفيذ الحالي ويُبذر seeded بواسطة نظام التشغيل، ونستدعي بعدها التابع <code>gen_range</code> على مولد الأرقام العشوائية، التابع السابق معرّف بالسمة <code>Rng</code> التي أضفناها إلى النطاق باستخدام التعليمة <code>use rand::Rng</code>. يأخذ التابع <code>gen_rang</code> تعبير مجال range expression مثل وسيط، ويولّد رقمًا ينتمي إلى ذلك المجال، إذ نستخدم تعبير المجال من النوع ذو التنسيق <code>start..=end</code>، ويتضمن المجال الحد الأعلى والأدنى داخله، لذا بكتابتنا للمجال "‎1..=100" فنحن نحدّد الأعداد بين 1 و100.
</p>

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

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

<p>
	جرّب تنفيذ البرنامج عدة مرات:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_77" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">2.53s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="str">`target/debug/guessing_game`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> secret number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">4</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln">

$ cargo run
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">0.02s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="str">`target/debug/guessing_game`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> secret number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">83</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">5</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span></pre>

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

<h2>
	مقارنة التخمين مع الرقم السري
</h2>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_79" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn 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"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

    let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

    io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

    match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"You win!"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p style="text-align: center;">
	[شيفرة 2-4: التعامل مع الحالات المُمكنة ضمن عملية المقارنة]
</p>

<p>
	نُضيف أولًا تعليمة <code>use</code> أخرى تقدّم لنا نوعًا جديدًا يدعى <code>std::cmp::Ordering</code> إلى النطاق من المكتبة القياسية، والنوع <code>Ordering</code> هو مُعدّد enum آخر يحتوي على المتغايرات <code>Less</code> و <code>Greater</code> و <code>Equal</code>، وهي النتائج الثلاث الممكنة عندما تُقارن ما بين قيمتين.
</p>

<p>
	نُضيف بعدها خمسة أسطر في النهاية، وتستخدم هذه الأسطر بدورها النوع <code>Ordering</code>، ويُقارن التابع <code>cmp</code> بين قيمتين ويُمكن استدعاؤه على أي شيء يمكن مقارنته، ويتطلب الأمر استخدام المرجع للشيء الذي تريد مقارنته، وفي حالتنا هذه فهو يقارن <code>guess</code> مع <code>secret_number</code>، ثم يُعيد متغايرًا من متغايرات المعدّد <code>Ordering</code> الذي أضفناه سابقًا إلى النطاق باستخدام تعليمة <code>use</code>، ونستخدم هنا تعبير <code>match</code> لتحديد ما الذي سنفعله لاحقًا بناءً على متغاير <code>Ordering</code> المُعاد من استدعاء <code>cmp</code> باستخدام القيمتين <code>guess</code> و <code>secret_number</code>.
</p>

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

<p>
	دعنا نوضح مثالًا عن تعبير <code>match</code> نستخدمه هنا؛ لنقُل أن المستخدم قد خمّن القيمة 50 وأن الرقم العشوائي السري المولّد كان 38، تُقارن شيفرتنا البرمجية القيمة 50 إلى 38 ويُعيد التابع <code>cmp</code> في هذه الحالة القيمة <code>Ordering::Greater</code> لأن 50 أكبر من 38، ويتلقّى التعبير <code>match</code> القيمة <code>Ordering::Greater</code> ويبدأ بتفقد كل نمط ذراع، إذ يُنظر إلى نمط الذراع الأولى وهو <code>Ordering::Less</code> وهي قيمةٌ لا توافق القيمة <code>Ordering::Greater</code> وبالتالي يجري تجاهل الشيفرة البرمجية ضمن الذراع وينتقل إلى نمط الذراع الأخرى وهو <code>Ordering::Greater</code> الذي يُطابق <code>!Ordering::Greater</code>، وبالتالي تُنفّذ الشيفرة البرمجية الموجود ضمن الذراع ويُطبع النص "Too big!‎" إلى الشاشة. ينتهي التعبير <code>match</code> بعد أول مطابقة ناجحة، لذا لن تجري المطابقة مع نمط الذراع الثالثة في هذه الحالة.
</p>

<p>
	إلا أن الشيفرة 2-4 لن تُصرّف، دعنا نجرّب ذلك:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_81" style=""><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> libc v0</span><span class="pun">.</span><span class="lit">2.86</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> getrandom v0</span><span class="pun">.</span><span class="lit">2.2</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> cfg</span><span class="pun">-</span><span class="kwd">if</span><span class="pln"> v1</span><span class="pun">.</span><span class="lit">0.0</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> ppv</span><span class="pun">-</span><span class="pln">lite86 v0</span><span class="pun">.</span><span class="lit">2.10</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand_core v0</span><span class="pun">.</span><span class="lit">6.2</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand_chacha v0</span><span class="pun">.</span><span class="lit">3.0</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> rand v0</span><span class="pun">.</span><span class="lit">8.3</span><span class="pln">
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
error</span><span class="pun">[</span><span class="pln">E0308</span><span class="pun">]:</span><span class="pln"> mismatched types
  </span><span class="pun">--&gt;</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">22</span><span class="pun">:</span><span class="lit">21</span><span class="pln">
   </span><span class="pun">|</span><span class="pln">
</span><span class="lit">22</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</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"> expected struct </span><span class="str">`String`</span><span class="pun">,</span><span class="pln"> found integer
   </span><span class="pun">|</span><span class="pln">
   </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">:</span><span class="pln"> expected reference </span><span class="str">`&amp;String`</span><span class="pln">
              found reference </span><span class="str">`&amp;{integer}`</span><span class="pln">

</span><span class="typ">For</span><span class="pln"> more information about this error</span><span class="pun">,</span><span class="pln"> try </span><span class="str">`rustc --explain E0308`</span><span class="pun">.</span><span class="pln">
error</span><span class="pun">:</span><span class="pln"> could </span><span class="kwd">not</span><span class="pln"> compile </span><span class="str">`guessing_game`</span><span class="pln"> due to previous error</span></pre>

<p>
	تتلخّص المشكلة الأساسية بوجود <strong>أنواع غير متوافقة mismatched types</strong>. لدى رست نظام نوع ساكن static type قوي، إلا أنها تحتوي أيضًا على واجهة نوع type interface، وبالتالي استنتجت رست عند كتابتنا للتعليمة <code>let mut guess = String::new()‎</code> بأن <code>guess</code> يجب أن تكون <code>String</code> ولم تُجبرنا على كتابة النوع، بينما <code>secret_number</code> على الجانب الآخر هو من نوع عددي وهناك عدد من أنواع رست الرقمية التي يمكن أن تحتوي على القيم بين 1 و100، مثل <code>i32</code> وهو عدد بطول 32 بت، و <code>u32</code> وهو عدد عديم الإشارة unsigned بطول 32 بت، و<code>i64</code> وهو عدد بطول 64 بت، إضافةً إلى أنواع أخرى، ويستخدم رست النوع <code>i32</code> افتراضيًا إن لم يُحدد النوع وهو نوع <code>secret_number</code> في هذه الحالة، والسبب في حدوث المشكلة هو عدم قدرة رست على المقارنة بين نوع عددي وسلسلة نصية.
</p>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_83" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

    let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

    io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

    let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Please type a number!"</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

    match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
        </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"You win!"</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	السطر الجديد هو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_85" style=""><span class="pln">let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Please type a number!"</span><span class="pun">);</span></pre>

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

<p>
	نُسند المتغير الجديد إلى التعبير <code>guess.trim().parse()‎</code>، إذ تشير <code>guess</code> ضمن التعبير إلى المتغير <code>guess</code> الأصلي الذي يحتوي على الدخل (سلسلة نصية string). يحذف التابع <code>trim</code> عند استخدامه ضمن نسخة من النوع <code>String</code> أي مسافات فارغة whitespaces في بداية ونهاية السلسلة النصية، وهو أمر لازم الحدوث قبل أن نحوّل السلسلة النصية إلى النوع <code>u32</code> الذي يمكن أن يحتوي فقط على قيمة عددية، وذلك لأن المستخدم يضغط على زرّ الإدخال enter لإنهاء عمل التابع <code>read_line </code>بعد إدخال تخمينه مما يُضيف محرف سطر جديد إلى السلسلة النصية؛ فعلى سبيل المثال، إذا أدخل المستخدم 5 وضغط على زر الإدخال، فستأخذ السلسلة النصية <code>guess </code>القيمة "‎5\n"، إذ يمثل المحرف "‎\n" محرف سطر جديد (يتسبب الضغط على زر الإدخال في أنظمة ويندوز برجوع السطر وإضافة سطر جديد "‎\r\n") ويُزيل التابع <code>trim</code> المحرف "‎\n" أو "‎\r\n" ونحصل بالتالي على "5" فقط.
</p>

<p>
	يحول التابع <a href="https://doc.rust-lang.org/stable/std/primitive.str.html#method.parse" rel="external nofollow"><code>parse</code></a> السلاسل النصية إلى نوع آخر، ونستخدمه هنا لتحويل السلسلة النصية إلى عدد، وعلينا إخبار رست بتحديد النوع الذي نريد التحويل إليه باستخدام <code>let guess: u32</code>، إذ تُشير النقطتان ":" الموجودتان بعد <code>guess</code> إلى أننا سنحدد نوع المتغير بعدها. تحتوي رست على عدد من الأنواع العددية المُضمّنة built-in منها <code>u32</code> الذي استخدمناه هنا وهو نوع عدد صحيح عديم الإشارة بطول 32-بت وهو خيار افتراضي جيّد للقيم الموجبة الصغيرة، وستتعلّم لاحقًا عن الأنواع العددية الأخرى. إضافةً إلى ما سبق، تعني <code>u32</code> في مثالنا والمقارنة مع <code>secret_number</code> أن رست سيستنتج أن <code>secret_number</code> يجب أن تكون من النوع <code>u32</code> أيضًا، لذا أصبحت المقارنة الآن بين قيمتين من النوع ذاته.
</p>

<p>
	يعمل التابع <code>parse</code> فقط على المحارف التي يمكن أن تُحوَّل منطقيًا إلى أعداد، لذلك من الشائع أن يتسبّب بأخطاء؛ فعلى سبيل المثال لن يستطيع التابع التحويل السلسلة النصية إلى نوع عددي إذا كانت تحتوي على القيمة "A?%‎" ولهذا السبب فإن التابع <code>parse</code> يُعيد أيضًا النوع <code>Result</code> بصورةٍ مماثلة للتابع <code>read_line</code>، الذي ناقشناه سابقًا في فقرة "التعامل مع الأخطاء الممكنة باستخدام النوع <code>Result</code>"، وسنتعامل مع النوع <code>Result</code> هذا بطريقة مماثلة باستخدام تابع <code>expect</code> مجددًا. إذا أعاد التابع <code>parse</code> متغاير <code>Result</code> المتمثل بالقيمة <code>Err</code> فهذا يعني أنه لم يستطع التحويل إلى نوع عددي من السلسلة النصية، وفي هذه الحالة، سيوقف استدعاء <code>expect</code> اللعبة وستُطبع الرسالة التي نمررها له، بينما يُعيد متغاير <code>Result</code> ذو القيمة <code>Ok</code> إذا استطاع تحويل القيمة بنجاح من نوع سلسلة نصية إلى نوع عددي، وتُعيد عندها <code>expect</code> العدد الذي نريده من قيمة <code>Ok</code>.
</p>

<p>
	دعنا نشغّل البرنامج الآن.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_89" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">0.43s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="str">`target/debug/guessing_game`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> secret number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">58</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
  </span><span class="lit">76</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">76</span><span class="pln">
</span><span class="typ">Too</span><span class="pln"> big</span><span class="pun">!</span></pre>

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

<p>
	تعمل اللعبة لدينا الآن جيدًا، إلا أن المستخدم يمكنه التخمين مرةً واحدةً فقط، دعنا نغيّر من ذلك بإضافة <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">حلقة تكرارية loop</a>.
</p>

<h2>
	السماح بعدة تخمينات باستخدام الحلقات التكرارية
</h2>

<p>
	تُنشئ الكلمة المفتاحية <code>loop</code> حلقةً تكراريةً لا نهائية، وسنستخدم الحلقة هنا بهدف منح المستخدم فرصًا أكبر في تخمين العدد:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_92" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">


        let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

        io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

        let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Please type a number!"</span><span class="pun">);</span><span class="pln">

        println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

        match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"You win!"</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>
	نقلنا محتوى البرنامج من تلقي الدخل guess إلى ما بعده لداخل الحلقة. تأكد من محاذاة السطور الموجودة داخل الحلقة التكرارية بمقدار أربع مسافات فارغة، وشغّل البرنامج مجددًا. سيسألك البرنامج الآن عن تخمين جديد إلى ما لا نهاية وهذه مشكلةٌ جديدة، إذ لن يستطيع المستخدم الخروج من البرنامج في هذه الحالة.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3486_94" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/guessing_game)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">1.50s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">guessing_game</span><span class="pun">`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> secret number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">59</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">45</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">45</span><span class="pln">
</span><span class="typ">Too</span><span class="pln"> small</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">60</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60</span><span class="pln">
</span><span class="typ">Too</span><span class="pln"> big</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">59</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">59</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> win</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
quit
thread </span><span class="str">'main'</span><span class="pln"> panicked at </span><span class="str">'Please type a number!: ParseIntError { kind: InvalidDigit }'</span><span class="pun">,</span><span class="pln"> src</span><span class="pun">/</span><span class="pln">main</span><span class="pun">.</span><span class="pln">rs</span><span class="pun">:</span><span class="lit">28</span><span class="pun">:</span><span class="lit">47</span><span class="pln">
note</span><span class="pun">:</span><span class="pln"> run </span><span class="kwd">with</span><span class="pln"> </span><span class="pun">`</span><span class="pln">RUST_BACKTRACE</span><span class="pun">=</span><span class="lit">1</span><span class="pun">`</span><span class="pln"> environment variable to display a backtrace</span></pre>

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

<h2>
	مغادرة اللعبة بعد إدخال التخمين الصحيح
</h2>

<p>
	دعنا نبرمج اللعبة بحيث نُغادر منها عند فوز المستخدم بإضافة تعليمة <code>break</code>:
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_96" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

        let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

        io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

        let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">().</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Please type a number!"</span><span class="pun">);</span><span class="pln">

        println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

        match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                println</span><span class="pun">!(</span><span class="str">"You win!"</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="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>break</code> بعد "You win!‎"، يخرج البرنامج من الحلقة عندما يكون تخمين المستخدم مساويًا إلى الرقم السري، ويعني الخروج من الحلقة أيضًا الخروج من البرنامج لأن الحلقة هي آخر جزء من الدالة <code>main</code>.
</p>

<h2>
	التعامل مع الدخل غير الصالح
</h2>

<p>
	دعنا نجعل البرنامج يتجاهل دخل المستخدم عندما يكون ذو قيمة غير عددية بدلًا من إيقافه لتحسين اللعبة أكثر، وذلك ليتسنّى للمستخدم إعادة إدخال التخمين بصورةٍ صحيحة. يمكننا تحقيق ما سبق عن طريق تغيير السطر الذي يحتوي على تحويل <code>guess</code> من <code>String</code> إلى <code>u32</code> كما توضح الشيفرة 2-5.
</p>

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_98" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    println</span><span class="pun">!(</span><span class="str">"The secret number is: {secret_number}"</span><span class="pun">);</span><span class="pln">

    loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

        let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">

        io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

        let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> match guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ok</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> num</span><span class="pun">,</span><span class="pln">
            </span><span class="typ">Err</span><span class="pun">(</span><span class="pln">_</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">

        println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">--</span><span class="pln">snip</span><span class="pun">--</span><span class="pln">


        match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                println</span><span class="pun">!(</span><span class="str">"You win!"</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="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 style="text-align: center;">
	[شيفرة 2-5: تجاهل تخمين غير عددي وسؤال المستخدم عن تخمين آخر بدلًا من إيقاف البرنامج]
</p>

<p>
	بدّلنا استدعاء التابع <code>expect</code> بتعبير <code>match</code> لتفادي إيقاف البرنامج والتعامل مع الخطأ. تذكر أن <code>parse</code> تُعيد قيمةً من نوع <code>Result</code> ويمثّل <code>Result</code> معدّدًا يحتوي على المغايرين <code>Ok</code> و <code>Err</code>. نستخدم هنا تعبير <code>match</code> بصورةٍ مماثلة لما فعلناه عند استخدام نتيجة <code>Ordering</code> في تابع <code>cmp</code>.
</p>

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

<p>
	إذا لم يكن التابع <code>parse</code> قادرًا على تحويل السلسلة النصية إلى عدد، فسيعيد قيمةً من النوع <code>Err</code> التي تحتوي بدورها على معلومات حول الخطأ، لا تُطابق قيمة <code>Err</code> نمط <code>Ok(num)‎</code> في ذراع <code>match</code> الأولى إلا أنها تطابق النمط <code>Err(_)‎</code> في الذراع الثانية، وترمز الشرطة السفلية <code>_</code> إلى الحصول على جميع القيم الممكنة، وفي مثالنا هذا فنحن نقول أننا نريد أن نطابق جميع قيم <code>Err</code> الممكنة بغض النظر عن المعلومات الموجودة داخلها، وبالتالي سينفذ البرنامج الذراع الثانية التي تتضمن على <code>continue</code> التي تخبر البرنامج بالذهاب إلى الدورة الثانية من الحلقة <code>loop</code> وأن تسأل المستخدم عن تخمينٍ آخر، لذا أصبح برنامجنا يتجاهل جميع أخطاء <code>parse</code> الممكنة بنجاح.
</p>

<p>
	يجب أن تعمل جميع أجزاء البرنامج كما هو متوقّع، لنجرّبه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_102" style=""><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> guessing_game v0</span><span class="pun">.</span><span class="lit">1.0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">file</span><span class="pun">://</span><span class="str">/projects/</span><span class="pln">guessing_game</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="lit">4.45s</span><span class="pln">
     </span><span class="typ">Running</span><span class="pln"> </span><span class="str">`target/debug/guessing_game`</span><span class="pln">
</span><span class="typ">Guess</span><span class="pln"> the number</span><span class="pun">!</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> secret number is</span><span class="pun">:</span><span class="pln"> </span><span class="lit">61</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">10</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
</span><span class="typ">Too</span><span class="pln"> small</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">99</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">99</span><span class="pln">
</span><span class="typ">Too</span><span class="pln"> big</span><span class="pun">!</span><span class="pln">
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
foo
</span><span class="typ">Please</span><span class="pln"> input your guess</span><span class="pun">.</span><span class="pln">
</span><span class="lit">61</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> guessed</span><span class="pun">:</span><span class="pln"> </span><span class="lit">61</span><span class="pln">
</span><span class="typ">You</span><span class="pln"> win</span><span class="pun">!</span></pre>

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

<p>
	اسم الملف: src/main.rs
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_3486_104" style=""><span class="pln">use rand</span><span class="pun">::</span><span class="typ">Rng</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">cmp</span><span class="pun">::</span><span class="typ">Ordering</span><span class="pun">;</span><span class="pln">
use std</span><span class="pun">::</span><span class="pln">io</span><span class="pun">;</span><span class="pln">

fn main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Guess the number!"</span><span class="pun">);</span><span class="pln">

    let secret_number </span><span class="pun">=</span><span class="pln"> rand</span><span class="pun">::</span><span class="pln">thread_rng</span><span class="pun">().</span><span class="pln">gen_range</span><span class="pun">(</span><span class="lit">1.</span><span class="pun">.=</span><span class="lit">100</span><span class="pun">);</span><span class="pln">

    loop </span><span class="pun">{</span><span class="pln">
        println</span><span class="pun">!(</span><span class="str">"Please input your guess."</span><span class="pun">);</span><span class="pln">

        let mut guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">::</span><span class="pln">new</span><span class="pun">();</span><span class="pln">

        io</span><span class="pun">::</span><span class="pln">stdin</span><span class="pun">()</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">read_line</span><span class="pun">(&amp;</span><span class="pln">mut guess</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">expect</span><span class="pun">(</span><span class="str">"Failed to read line"</span><span class="pun">);</span><span class="pln">

        let guess</span><span class="pun">:</span><span class="pln"> u32 </span><span class="pun">=</span><span class="pln"> match guess</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">().</span><span class="pln">parse</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ok</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> num</span><span class="pun">,</span><span class="pln">
            </span><span class="typ">Err</span><span class="pun">(</span><span class="pln">_</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">

        println</span><span class="pun">!(</span><span class="str">"You guessed: {guess}"</span><span class="pun">);</span><span class="pln">

        match guess</span><span class="pun">.</span><span class="pln">cmp</span><span class="pun">(&amp;</span><span class="pln">secret_number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Less</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too small!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Greater</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> println</span><span class="pun">!(</span><span class="str">"Too big!"</span><span class="pun">),</span><span class="pln">
            </span><span class="typ">Ordering</span><span class="pun">::</span><span class="typ">Equal</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                println</span><span class="pun">!(</span><span class="str">"You win!"</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">break</span><span class="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 style="text-align: center;">
	[شيفرة 2-6: الشيفرة البرمجية للعبة التخمين كاملةً]
</p>

<h2>
	ملخص
</h2>

<p>
	أنهينا بالوصول إلى هذه النقطة لعبة التخمين كاملةً، تهانينا.
</p>

<p>
	كان هذا المشروع بمثابة تطبيق عملي وطريقة للتعرف على مفاهيم رست الجديدة، مثل <code>let</code> و <code>match</code> والدوال واستخدام الصناديق الخارجية وغيرها. ستتعلم المزيد عن هذه المفاهيم بالتفصيل فيما يتبع، إذ سنتكلم عن المفاهيم الموجودة في معظم لغات البرمجة، مثل المتغيرات وأنواع البيانات والدوال وسنستعرض كيفية استخدامها في لغة رست، ثم سنتوجه لمناقشة مفهوم الملكية ownership وهي ميزة تجعل من لغة رست مميّزة دونًا عن لغات البرمجة الأخرى، ومن ثمّ سنناقش صيغة syntax التابع والهياكل structs، ومن ثمّ سنشرح كيفية عمل المعدّدات enums.
</p>

<p>
	ترجمة -وبتصرف- لفصل <a href="https://doc.rust-lang.org/stable/book/ch02-00-guessing-game-tutorial.html/" rel="external nofollow">Programming a Guessing Game</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-r1779/" rel="">المتغيرات والتعديل عليها في لغة رست</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/" rel="">تعلم لغة رست Rust: البدايات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/learn-programming/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		تعرف على أشهر<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel=""> لغات برمجة الألعاب</a><br>
		 
	</li>
</ul>
]]></description><guid isPermaLink="false">1765</guid><pubDate>Thu, 10 Nov 2022 16:04:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x645; &#x644;&#x63A;&#x629; &#x631;&#x633;&#x62A; Rust: &#x627;&#x644;&#x628;&#x62F;&#x627;&#x64A;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/rust/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A7%D8%AA-r1764/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636393b9050cb_---.png.48ac143a1c2b377333abe18d09cc2b06.png" /></p>
<p>
	ادعنا نبدأ رحلتنا مع لغة رست، إذ هناك الكثير لنتعلمه، وعلى كل رحلة أن تبدأ في مكان ما. سنناقش في هذا المقال كلًا من التالي:
</p>

<ul>
	<li>
		تثبيت لغة رست على <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> وماك أو إس macOS وويندوز Windows.
	</li>
	<li>
		كتابة برنامج يطبع العبارة "Hello, world!‎".
	</li>
	<li>
		استخدام أداة كارجو cargo، مدير حزم لغة رست package manager ونظام بنائها build system.
	</li>
</ul>

<h2>
	تثبيت لغة رست
</h2>

<p>
	أولى خطواتنا هنا هي تثبيت لغة رست هي بتنزيل رست عن طريق أداة سطر الأوامر <code>rustup</code>، التي تدير إصدارات رست والأدوات المرتبطة بها، وستحتاج لاتصال <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>

<p>
	<strong>ملاحظة</strong>: إذا كنت لا تفضل استخدام <code>rustup</code> لسبب ما، اطّلع على <a href="https://forge.rust-lang.org/infra/other-installation-methods.html" rel="external nofollow">هذه الصفحة</a> للمزيد من الخيارات لتثبيت لغة رست.
</p>

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

<h3>
	الإشارة إلى سطر الأوامر
</h3>

<p>
	سنستعرض بعض <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">الأوامر المُستخدمة في الطرفية terminal</a> ضمن هذا المقال والسلسلة ككُل، إذ تبدأ الأسطر التي يجب أن تُدخلها بالرمز "$"، وليس عليك هنا أن تكتب الرمز "$"، الذي يدل على بداية أمر جديد، وعادةً ما تعرض الأسطر التي لا تبدأ بهذا الرمز الخرج لأمر سابق. إضافةً لما سبق، تستخدم الأمثلة التي تعتمد على صدفة Shell‏ PowerShell خصوصًا الرمز "&lt;" بدلًا من "$".
</p>

<h3>
	تثبيت أداة سطر الأوامر rustup على لينكس أو ماك أو إس
</h3>

<p>
	إذا كنت تستخدم نظام لينكس أو ماك أو إس، افتح الطرفية لإدخال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_11"><span class="pln">$ curl </span><span class="pun">--</span><span class="pln">proto </span><span class="str">'=https'</span> <span class="pun">--</span><span class="pln">tlsv1</span><span class="pun">.</span><span class="lit">3</span><span class="pln"> https</span><span class="pun">:</span><span class="com">//sh.rustup.rs -sSf | sh</span></pre>

<p>
	سينزّل الأمر السابق سكريبتًا script ويبدأ بتثبيت أداة <code>rustup</code> التي ستثبّت بدورها آخر إصدارات لغة رست المستقرة، وقد يُطلب منك كلمة المرور لحسابك. إذا انتهت عملية التثبيت بنجاح، ستجد السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_13"><span class="typ">Rust</span><span class="pln"> is installed now</span><span class="pun">.</span> <span class="typ">Great</span><span class="pun">!</span></pre>

<p>
	ستحتاج أيضًا إلى <strong>رابط linker</strong>، وهو برنامج يستخدمه رست لضمّ الخرج المُصرَّف إلى ملف واحد، وسيكون موجودًا غالبًا لديك. يجب عليك تثبيت <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="">مصرف سي C</a> الذي يتضمن عادةً على رابط، إذا حصلت على أخطاء رابط، كما أن مصرف سي مفيد أيضًا لاعتماد بعض حزم لغة راست الشائعة على شيفرة لغة سي.
</p>

<p>
	يمكنك الحصول على مصرف سي على نظام ماك أو إس بكتابة الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6806_16"><span class="pln">$ xcode</span><span class="pun">-</span><span class="kwd">select</span> <span class="pun">--</span><span class="pln">install</span></pre>

<p>
	يجب أن يثبت مستخدمو نظام لينكس GCC أو Clang اعتمادًا على توثيق التوزيعة distribution؛ فإذا كنت تستخدم مثلًا توزيعة أوبنتو Ubuntu، فيمكنك تثبيت حزمة <code>build-essential</code>.
</p>

<h3>
	تثبيت أداة سطر الأوامر rustup على ويندوز
</h3>

<p>
	إن كنت تستخدم نظام ويندوز، اذهب إلى <a href="https://www.rust-lang.org/tools/install" rel="external nofollow">www.rust-lang.org/tools/install</a>، واتبّع التعليمات لتثبيت لغة رست، إذ ستستلم في مرحلة ما من مراحل التثبيت رسالةً مفادها أنك ستحتاج إلى أدوات بناء C++‎ الخاصة ببرنامج فيجوال ستوديو Visual Studio إصدار 2013 أو ما بعده، والطريقة الأسهل في الحصول على أدوات البناء هذه هي بتثبيتها مباشرةً من <a href="https://visualstudio.microsoft.com/visual-cpp-build-tools/" rel="external nofollow">Visual Studio 2022</a>، وتأكد من اختيار "C++ build tools" عند سؤالك عن أي الإصدارات التي تريد تثبيتها وتأكد أيضًا من تضمين حزمة Windows 10 SDK وحزمة اللغة الإنجليزية إلى جانب أي حزمة لغة أخرى من اختيارك.
</p>

<p>
	يستخدم باقي الكتاب أوامر تعمل في كلٍّ من "cmd.exe" وصدفة PowerShell، وإذا كانت هناك أي فروقات معينة سنشرح أيهما يجب أن تستخدم.
</p>

<h3>
	التحديث والتثبيت في لغة رست
</h3>

<p>
	تُعد عملية التحديث بعد تثبيت لغة رست باستخدام <code>rustup</code> عمليةً سهلة، فكل ما يجب عليك فعله هو تنفيذ سكريبت التحديث من الصدفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_18"><span class="pln">$ rustup update</span></pre>

<p>
	لإزالة تثبيت لغة رست وأداة <code>rustup</code>، نفذ سكريبت إزالة التثبيت من الصدفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_20"><span class="pln">$ rustup self uninstall</span></pre>

<h3>
	استكشاف الأخطاء وإصلاحها في لغة رست
</h3>

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

<pre class="ipsCode">$ rustc --version
</pre>

<p>
	من المفترض أن تجد رقم الإصدار وقيمة الإيداع المُعمّاة commit hash وتاريخ الإيداع لآخر إصدار مستقر جرى إطلاقه بالتنسيق التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_22"><span class="pln">rustc x</span><span class="pun">.</span><span class="pln">y</span><span class="pun">.</span><span class="pln">z </span><span class="pun">(</span><span class="pln">abcabcabc yyyy</span><span class="pun">-</span><span class="pln">mm</span><span class="pun">-</span><span class="pln">dd</span><span class="pun">)</span></pre>

<p>
	إذا ظهر لك السطر السابق، فهذا يعني أنك ثبّتتَ لغة رست بنجاح؛ وإذا لم تجد هذه المعلومات وكنت تستخدم نظام ويندوز، فتأكد أن راست موجود في متغير النظام system variable المسمى <code>%PATH%</code>كما يلي:
</p>

<p>
	إذا كنت تستخدم نظام تشغيل ويندوز، اكتب في واجهة سطر أوامر CMD ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_24"><span class="pun">&gt;</span><span class="pln"> echo </span><span class="pun">%</span><span class="pln">PATH</span><span class="pun">%</span></pre>

<p>
	أما في صدفة PowerShell، استخدم السطر التالي:
</p>

<pre class="ipsCode">&gt; echo $env:Path
</pre>

<p>
	وفي نظام تشغيل لينكس وماك أو إس، استخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_26"><span class="pln">$ echo $PATH</span></pre>

<p>
	إذا كان كل شيء صحيحًا، ورست لا يعمل فهناك عددٌ من الأماكن التي تستطيع الحصول منها على مساعدة، إذ يمكنك مثلًا طرح مشكلتك في قسم <a href="https://academy.hsoub.com/questions/c3-programming/" rel="">الأسئلة والأجوبة</a> في أكاديمية حسوب أو إن أردت يمكنك التواصل مع فريق لغة رست مباشرة عبر <a href="https://www.rust-lang.org/community" rel="external nofollow">صفحة التواصل</a>.
</p>

<h3>
	التوثيق المحلي للغة رست
</h3>

<p>
	يتضمن تثبيت لغة رست أيضًا نسخةً محليةً من التوثيق documentation لتتمكّن من قراءتها دون اتصال بالإنترنت، ولفتح النسخة ضمن المتصفح، نفذ الأمر <code>rustup doc</code>.
</p>

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

<h2>
	كتابة أول برنامج بلغة رست
</h2>

<p>
	الآن، وبعد الانتهاء من تثبيت لغة رست، يمكنك كتابة أول برنامج. من المتعارف عليه عند تعلم لغة برمجة جديدة هو كتابة برنامج بسيط يطبع السلسلة النصية "Hello, world!‎" على الشاشة، لذا دعنا ننجز ذلك.
</p>

<p>
	<strong>ملاحظة</strong>: يفترض هذا الكتاب معرفتك بأساسيات <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>، ولا تتطلب لغة رست طريقةً معينةً لكيفية تعديلك أو استخدامك للأدوات أو مكان وجود شيفرتك البرمجية، لذا يمكنك استخدام بيئة برمجية متكاملة integrated development environment -أو اختصارًا IDE- إذا أردت، ولك الحرية في اختيار ما هو مفضّل لك. هناك العديد من البيئات البرمجية المتكاملة التي تقدم دعمًا للغة راست، ويمكنك تفقّد توثيق البيئة البرمجية المتكاملة التي اخترتها لمزيدٍ من التفاصيل. يحاول فريق تطوير لغة رست مؤخرًا توجيه جهودهم نحو تمكين دعم جيد للبيئات البرمجية المتكاملة عن طريق <code>rust-analyzer</code>.
</p>

<h3>
	إنشاء مجلد لمشروع بلفة رست
</h3>

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

<p>
	افتح الطرفية وأدخِل الأوامر التالية لإنشاء مجلد "projects" ومجلد لمشروع "Hello, world!‎" ضمن المجلد "projects".
</p>

<p>
	لمستخدمي نظام لينكس وماك أو إس وصدفة PowerShell على نظام ويندوز، أدخل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_28"><span class="pln">$ mkdir </span><span class="pun">~/</span><span class="pln">projects
$ cd </span><span class="pun">~/</span><span class="pln">projects
$ mkdir hello_world
$ cd hello_world</span></pre>

<p>
	ولطرفية ويندوز CMD، أدخل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_30"><span class="pun">&gt;</span><span class="pln"> mkdir </span><span class="str">"%USERPROFILE%\projects"</span>
<span class="pun">&gt;</span><span class="pln"> cd </span><span class="pun">/</span><span class="pln">d </span><span class="str">"%USERPROFILE%\projects"</span>
<span class="pun">&gt;</span><span class="pln"> mkdir hello_world
</span><span class="pun">&gt;</span><span class="pln"> cd hello_world</span></pre>

<h3>
	كتابة وتشغيل برنامج بلغة رست
</h3>

<p>
	أنشئ ملفًا مصدريًا جديدًا وسمّه باسم "main.rs"، إذ يجب أن تنتهي ملفات شيفرة لغة رست بالامتداد "‎.rs" دائمًا، وإذا كنت تستخدم أكثر من كلمة واحدة في اسم الملف، فاستخدم الشرطة السفلية underscore للفصل ما بين الكلمات، فعلى سبيل المثال استخدم الاسم "hello_world.rs" بدلًا من "helloworld.rs".
</p>

<p>
	الآن افتح ملف "main.rs" الذي أنشأته لتوك وأدخِل الشيفرة التالية:
</p>

<pre class="ipsCode">fn main() {
    println!("Hello, world!");
}
</pre>

<p style="text-align: center;">
	[شيفرة 1: برنامج يطبع "Hello, world!‎"]
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_32"><span class="pln">$ rustc main</span><span class="pun">.</span><span class="pln">rs
$ </span><span class="pun">./</span><span class="pln">main
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

<p>
	إذا كنت تستخدم نظام ويندوز أدخل الأمر <code>‎.\main.exe</code> بدلًا من <code>‎./main</code>:
</p>

<pre class="ipsCode">&gt; rustc main.rs
&gt; .\main.exe
Hello, world!
</pre>

<p>
	يجب أن تحصل على السلسلة النصية "Hello,world!‎" مطبوعةً على الطرفية بغض النظر عن <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام تشغيلك</a>، وإن لم يظهر الخرج، فعُد إلى فقرة استكشاف الأخطاء وإصلاحها لطرق الحصول على مساعدة.
</p>

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

<h3>
	أجزاء برنامج لغة رست
</h3>

<p>
	دعنا نطّلع بالتفصيل على الأشياء التي تحدث في برنامج "Hello, world!‎"، إليك أول الأجزاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_35"><span class="pln">fn main</span><span class="pun">()</span> <span class="pun">{</span>

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

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

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

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

<p>
	نجد داخل دالة <code>main</code> الشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_37"><span class="pln">    println</span><span class="pun">!(</span><span class="str">"Hello, world!"</span><span class="pun">);</span></pre>

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

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

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

<p>
	ثالثًا، السلسلة النصية <code>"Hello, world!‎"</code> تُمرّر وسيطًا <code>argument</code> للماكرو<code> !println</code>، ثمّ تُطبع السلسلة النصية على الشاشة.
</p>

<p>
	رابعًا، نُنهي السطر بالفاصلة المنقوطة (;) وذلك يُشير إلى انتهاء ذلك التعبير expression وأن التعبير التالي سيبدأ من بعده، وتنتهي معظم أسطر شيفرة لغة رست بالفاصلة المنقوطة.
</p>

<h3>
	تصريف البرنامج وتشغيله في لغة رست
</h3>

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

<p>
	قبل تشغيل برنامج رست، يجب عليك تصريفه باستخدام مصرف لغة رست بإدخال الأمر <code>rustc</code> وتمرير اسم الملف المصدري كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_40"><span class="pln">$ rustc main</span><span class="pun">.</span><span class="pln">rs</span></pre>

<p>
	إذا كان لديك معرفة سابقة <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/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++‎</a>، فستلاحظ أن هذا مماثل لاستخدام الأمر <code>gcc</code> أو <code>clang</code>. بعد التصريف بنجاح، يُخرج رست ملفًا ثنائيًا تنفيذيًا binary executable.
</p>

<p>
	يمكنك رؤية الملف التنفيذي على نظام لينكس أو ماك أو إس أو صدفة PowerShell على ويندوز عبر تنفيذ الأمر <code>ls</code>، وستجد في نظامَي لينكس وماك أو إس ملفين، بينما ستجد ثلاث ملفات إذا كنت تستخدم صدفة PowerShell وهي الملفات ذاتها التي ستجدها عند استخدامك طرفية CMD على ويندوز.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_44"><span class="pln">$ ls
main  main</span><span class="pun">.</span><span class="pln">rs</span></pre>

<p>
	أدخل في طرفية CMD على ويندوز ما يلي (يعني الخيار <code>‎/B‎</code> أننا نريد فقط عرض أسماء الملفات):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_50"><span class="pun">&gt;</span><span class="pln"> dir </span><span class="pun">/</span><span class="pln">B 
main</span><span class="pun">.</span><span class="pln">exe
main</span><span class="pun">.</span><span class="pln">pdb
main</span><span class="pun">.</span><span class="pln">rs</span></pre>

<p>
	يعرض ما سبق شيفرة الملف المصدر بامتداد "‎.rs"، إضافةً إلى الملف التنفيذي (المسمى main.exe على ويندوز و main على بقية المنصات)، وعند استخدام ويندوز هناك ملف يحتوي على معلومات لتصحيح الأخطاء بامتداد "‎.‎‎pdb‎‎‎"، ويمكنك تشغيل الملف التنفيذي "main" أو "main.exe" على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_52"><span class="pln">$ </span><span class="pun">./</span><span class="pln">main </span><span class="pun">#</span> <span class="pun">‫‫أو</span> <span class="pun">‎.</span><span class="pln">\main</span><span class="pun">.</span><span class="pln">exe </span><span class="pun">على</span> <span class="pun">ويندوز</span></pre>

<p>
	إذا كان "main.rs" هو برنامج "Hello, world!‎" فسيطبع السطر السابق "Hello, world!‎" على طرفيتك.
</p>

<p>
	قد لا تكون معتادًا على كون جزء التصريف خطوة مستقلة إذا كنت تألف لغة ديناميكية، مثل <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="">روبي Ruby</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="">بايثون Python</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="">جافاسكربت JavaScript</a>. تعدّ لغة رست لغة مُصرّفة سابقة للوقت ahead-of-time compiled language، مما يعني أن البرنامج يُصرّف وينتج عن ذلك ملف تنفيذي يُمنح لأحد آخر، بحيث يمكن له تشغيله دون وجود لغة رست عنده، وعلى النقيض تمامًا إذا أعطيت أحدًا ما ملفًا بامتداد "‎.rb" أو "‎.py" أو "‎.js" فلن يستطيع تشغيله إن لم يتواجد تطبيق <a href="https://wiki.hsoub.com/Ruby" rel="external">روب</a>ي أو <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> أو <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> مثبتًا عنده، والفارق هنا هو أنه عليك استخدام أمرٍ واحد فقط لتصريف وتشغيل البرنامج. تصميم لغات البرمجة مبني على المقايضات.
</p>

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

<h2>
	نظام بناء لغة رست "مرحبا كارجو"
</h2>

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

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_60"><span class="pln">$ cargo </span><span class="pun">--</span><span class="pln">version</span></pre>

<p>
	إذا ظهر لك رقم الإصدار، فهذا يعني أنه موجود. إذا ظهرت رسالة خطأ مثل "command not found"، ألقِ نظرةً على توثيق طريقة التثبيت التي اتبعتها لمعرفة طريقة تثبيت كارجو بصورةٍ منفصلة.
</p>

<h3>
	إنشاء مشروع للغة رست باستخدام كارجو
</h3>

<p>
	دعنا نُنشئ مشروعًا جديدًا باستخدام كارجو ونُقارن بين هذه الطريقة وطريقتنا السابقة في إنشاء مشروع "Hello, world!‎". انتقل إلى مجلد "projects" (أو أي اسم مغاير اخترته لتخزّن فيه شيفرتك البرمجية)، ثم نفذ الأوامر التالية (بغض النظر عن نظام تشغيلك):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_62"><span class="pln">$ cargo </span><span class="kwd">new</span><span class="pln"> hello_cargo
$ cd hello_cargo</span></pre>

<p>
	يُنشئ الأمر الأول مجلدًا جديدًا باسم "hello_cargo" -إذ أننا اخترنا تسمية "hello_cargo" لمشروعنا- ومن ثم يُنشئ كارجو ملفاته في المجلد الذي اخترناه بذات الاسم.
</p>

<p>
	اذهب إلى المجلد "hello_cargo" واعرض الملفات الموجودة فيه، ستجد أن كارجو قد أنشأ ملفين ومجلدًا واحدًا داخله، هم: ملف باسم "cargo.toml"، ومجلد "src"، وملف "main.rs"؛ كما أنه هيأ مستودع <a href="https://academy.hsoub.com/programming/workflow/git/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9%D9%8A-%D9%84%D9%84%D8%B9%D9%85%D9%84-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%BA%D9%8A%D8%AA-git-r1587/" rel="">غيت Git</a> جديد مع ملف "‎.gitignore". لن تُوَلّد ملفات غيت إذا استخدمت الأمر <code>cargo new</code> ضمن مستودع جيت موجود مسبقًا، ويمكنك تجاوز ذلك السلوك عن طريق استخدام الأمر <code>cargo new --vcs=git</code>.
</p>

<p>
	<strong>ملاحظة</strong>: غيت هو نظام شائع للتحكم بالإصدارات، ويمكنك تغيير نظام التحكم بالإصدارات عند تنفيذ الأمر <code>cargo new</code> بإضافة الراية <code>‎--vcs</code>. يمكنك تنفيذ الأمر <code>cargo new --help</code> إذا أردت رؤية الخيارات المتاحة.
</p>

<p>
	افتح الملف "Cargo.toml" باستخدام محرر النصوص المفضل لديك، يجب أن تكون الشيفرة البرمجية بداخله مشابهة للشيفرة 1-2.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_65"><span class="pun">[</span><span class="pln">package</span><span class="pun">]</span><span class="pln">
name </span><span class="pun">=</span> <span class="str">"hello_cargo"</span><span class="pln">
version </span><span class="pun">=</span> <span class="str">"0.1.0"</span><span class="pln">
edition </span><span class="pun">=</span> <span class="str">"2021"</span>

<span class="pun">[</span><span class="pln">dependencies</span><span class="pun">]</span></pre>

<p style="text-align: center;">
	[الشيفرة 1-2: محتوى ملف Cargo.toml الناتج عن تنفيذ الأمر <code>cargo new</code>]
</p>

<p>
	يمكنك الاطلاع على مزيدٍ من المفاتيح وتعريفاتها على <a href="https://doc.rust-lang.org/cargo/reference/manifest.html" rel="external nofollow">الرابط</a>.
</p>

<p>
	هذا الملف مكتوب بتنسيق لغة <a href="https://toml.io/" rel="external nofollow">TOML</a> (اختصارًا للغة توم المُختصرة الواضحة Tom's Obvious, Minimal Langaug)، وهي لغة تنسيق كارجو.
</p>

<p>
	يمثل السطر الأول <code>[package]</code> قسم ترويسة الذي يشير إلى أن ما يليه هي معلومات لإعداد الحزمة. نُضيف المزيد من الأقسام إذا أردنا إضافة المزيد من المعلومات إلى هذا الملف.
</p>

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

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

<p>
	أما الآن فافتح الملف "main.rs" الموجود داخل المجلد "src" وألقِ نظرةً على ما داخله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_67"><span class="pln">fn main</span><span class="pun">()</span> <span class="pun">{</span><span class="pln">
    println</span><span class="pun">!(</span><span class="str">"Hello, world!"</span><span class="pun">);</span>
<span class="pun">}</span></pre>

<p>
	قد ولّد كارجو برنامج "!Hello, world" لك على نحوٍ مماثل للبرنامج الذي كتبناه سابقًا في الشيفرة 1-1، والاختلاف الوحيد حتى اللحظة بين مشروعنا السابق ومشروع كارجو هو أن كارجو أضاف الشيفرة البرمجية داخل مجلد "src" وأنه لدينا ملف الإعداد "Cargo.toml" في المجلد الرئيسي.
</p>

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

<p>
	يمكنك تحويل مشروعك إلى مشروع يستخدم كارجو إذا أنشأت مشروعًا جديدًا دون استخدام كارجو على نحوٍ مماثل لما فعلناه في مشروع "!Hello, world"، فكل ما عليك فعله هو نقل الشيفرة المصدرية الخاصة بالمشروع إلى مجلد "src" وإنشاء ملف "Cargo.toml" موافق لتفاصيل المشروع.
</p>

<h3>
	بناء وتشغيل مشروع كارجو
</h3>

<p>
	دعنا ننظر الآن إلى ما هو مختلف عندما نشغّل برنامج "!Hello, world" باستخدام كارجو. أنشئ مشروعك بإدخال الأمر التالي داخل المجلد "hello_cargo":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_69"><span class="pln">$ cargo build
   </span><span class="typ">Compiling</span><span class="pln"> hello_cargo v0</span><span class="pun">.</span><span class="lit">1.0</span> <span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/hello_cargo)</span>
    <span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">2.85</span><span class="pln"> secs</span></pre>

<p>
	يُنشئ الأمر السابق ملف تنفيذي ضمن المجلد "target/debug/hello_cargo" (أو "target\debug\hello_cargo.exe" على ويندوز) بدلًا عن مجلدك الحالي، ويمكنك تشغيل الملف التنفيذي باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_71"><span class="pln">$ </span><span class="pun">./</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">hello_cargo  </span><span class="pun">#</span> <span class="pun">‫أو</span> <span class="pun">‎.</span><span class="pln">\target\debug\hello_cargo</span><span class="pun">.</span><span class="pln">exe </span><span class="pun">على</span> <span class="pun">ويندوز</span>
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

<p>
	إذا مر كل ما سبق بنجاح فستُطبع "Hello, world!‎" على الطرفية. يتسبب تنفيذ الأمر <code>cargo build</code> للمرة الأولى بإنشاء كارجو لملف جديد في المجلد الرئيسي باسم "Cargo.lock" وهذا الملف يتابع إصدارات الاعتماديات المستخدمة في مشروعك، وبما أن هذا المشروع لا يحتوي على أي اعتماديات، فلن يكون هذا الملف ذا أهمية كبيرة، إلا أن هذا يعني أنه لا يوجد أي حاجة لتغيير محتويات هذا الملف يدويًا بل يتكفل كارجو بمحتوياته بدلًا عنك.
</p>

<p>
	بنينا لتوّنا مشروعًا باستخدام <code>cargo build</code> وشغّلناه باستخدام الأمر <code>‎./target/debug/hello_cargo</code>، إلا أنه يمكننا استخدام الأمر <code>cargo run</code> أيضًا لتصريف الشيفرة البرمجية وتشغيلها مما ينتج عن تشغيل الملف التنفيذ باستخدام أمر واحد فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_75"><span class="pln">$ cargo run
    </span><span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.0</span><span class="pln"> secs
     </span><span class="typ">Running</span> <span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">hello_cargo</span><span class="pun">`</span>
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

<p>
	يستخدم معظم المطورين <code>cargo run</code> لأنه أكثر ملاءمةً من تذكُّر تشغيل <code>cargo build</code> ثم استخدام المسار الكامل وصولًا للملف الثنائي (التنفيذي).
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_78"><span class="pln">$ cargo run
   </span><span class="typ">Compiling</span><span class="pln"> hello_cargo v0</span><span class="pun">.</span><span class="lit">1.0</span> <span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/hello_cargo)</span>
    <span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.33</span><span class="pln"> secs
     </span><span class="typ">Running</span> <span class="pun">`</span><span class="pln">target</span><span class="pun">/</span><span class="pln">debug</span><span class="pun">/</span><span class="pln">hello_cargo</span><span class="pun">`</span>
<span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!</span></pre>

<p>
	يحتوي كارجو أيضًا على أمر آخر وهو <code>cargo check</code>، ويتحقق هذا الأمر من شيفرتك البرمجية للتأكد من أنها ستُصرّف بنجاح ولكنه لا يولّد أي ملف تنفيذي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_80"><span class="pln">$ cargo check
   </span><span class="typ">Checking</span><span class="pln"> hello_cargo v0</span><span class="pun">.</span><span class="lit">1.0</span> <span class="pun">(</span><span class="pln">file</span><span class="pun">:</span><span class="com">///projects/hello_cargo)</span>
    <span class="typ">Finished</span><span class="pln"> dev </span><span class="pun">[</span><span class="pln">unoptimized </span><span class="pun">+</span><span class="pln"> debuginfo</span><span class="pun">]</span><span class="pln"> target</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> in </span><span class="lit">0.32</span><span class="pln"> secs</span></pre>

<p>
	لكن في أيّ الحالات لن تحتاج إلى ملف تنفيذي؟ يكون الأمر <code>cargo check</code> أسرع غالبًا في تنفيذه من الأمر <code>cargo build</code> لأنه يتخطى مرحلة توليد الملف التنفيذي، وبالتالي إذا أردت التحقق باستمرار من صحة شيفرتك البرمجية خلال كتابتها فاستخدام <code>cargo check</code> سيُسرّع العملية بصورةٍ ملحوظة. ينفّذ معظم مستخدمي لغة رست الأمر <code>cargo check</code> دوريًا عادةً للتأكد من صحة شيفرتهم البرمجية ومن أنها ستُصرّف دون مشاكل، ثمّ ينفذون الأمر <code>cargo build</code> عندما يحين الوقت لتوليد ملف تنفيذي واستخدامه.
</p>

<p>
	دعنا نلخّص ما تعلمناه لحد اللحظة بخصوص كارجو:
</p>

<ul>
	<li>
		نُنشئ المشاريع باستخدام الأمر <code>cargo new</code>.
	</li>
	<li>
		نبني المشروع باستخدام الأمر <code>cargo build</code>.
	</li>
	<li>
		نستطيع بناء المشروع وتشغيله بأمر واحد وهو <code>cargo run</code>.
	</li>
	<li>
		يمكننا بناء المشروع دون توليد ملف تنفيذي ثنائي بهدف التحقق من الأخطاء في الشيفرة البرمجية باستخدام الأمر <code>cargo check</code>.
	</li>
	<li>
		يخزن كارجو ناتج عملية البناء في المجلد "target/debug" عوضًا عن تخزينها في مجلد الشيفرة البرمجية ذاتها.
	</li>
</ul>

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

<h3>
	بناء المشروع لإطلاقه
</h3>

<p>
	يمكنك استخدام الأمر <code>cargo build --release</code> عندما يصل مشروعك إلى مرحلة الإطلاق لتصريفه بصورةٍ مُحسّنة، وسيولّد هذا الأمر ملفًا تنفيذيًا في المجلد "target/release" بدلًا من المجلد "target/debug"، ويزيد التحسين من سرعة تنفيذ شيفرتك البرمجية إلا أن عملية تصريفه ستستغرق وقتًا أطول، وهذا السبب في تواجد خيارين لبناء المشروع: أحدهما هو بهدف التطوير عندما تحتاج لبناء المشروع بسرعة وبصورةٍ دورية والآخر لبناء النسخة النهائية من البرنامج التي ستعطيها إلى المستخدم وفي هذه الحالة لن تُصرّف البرنامج دوريًا وسيكون البرنامج الناتج أسرع ما يمكن. إذا أردت قياس الوقت الذي تستغرقه شيفرتك البرمجية لتُنفّذ، استخدم الأمر <code>cargo build --release</code> وقِس الوقت باستخدام الملف التنفيذي الموجود في المجلد "target/release".
</p>

<h3>
	أداة كارجو مثل أداة عرض
</h3>

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

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6806_84"><span class="pln">$ git clone example</span><span class="pun">.</span><span class="pln">org</span><span class="pun">/</span><span class="pln">someproject
$ cd someproject
$ cargo build</span></pre>

<p>
	لمزيدٍ من المعلومات حول كارجو، انظر إلى <a href="https://doc.rust-lang.org/cargo/" rel="external nofollow">التوثيق</a>.
</p>

<h2>
	ملخص
</h2>

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

<ul>
	<li>
		تثبيت آخر إصدارات لغة رست المستقرة باستخدام <code>rustup</code>.
	</li>
	<li>
		تحديث إصدار لغة رست الموجود إلى آخر جديد.
	</li>
	<li>
		فتح التوثيق المحلي (دون اتصال بالإنترنت).
	</li>
	<li>
		كتابة وتشغيل برنامج "!Hello, world" باستخدام <code>rustc</code> مباشرةً.
	</li>
	<li>
		إنشاء وتشغيل برنامج جديد باستخدام أداة كارجو.
	</li>
</ul>

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

<p>
	ترجمة -وبتصرف- لفصل <a href="https://doc.rust-lang.org/stable/book/ch01-00-getting-started.html/" rel="external nofollow">Getting Started</a> من كتاب <a href="https://doc.rust-lang.org/stable/book/title-page.html/" rel="external nofollow">The Rust Programming Language</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/rust/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D8%AE%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D8%B1%D9%82%D8%A7%D9%85-%D8%A8%D9%84%D8%BA%D8%A9-%D8%B1%D8%B3%D8%AA-rust-r1765/" rel="">برمجة لعبة تخمين الأرقام بلغة رست Rust</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<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>
	</li>
</ul>
]]></description><guid isPermaLink="false">1764</guid><pubDate>Thu, 03 Nov 2022 16:08:00 +0000</pubDate></item></channel></rss>
