في Rust، يُسمّى إعطاء قيمة لاسم ارتباطًا. الارتباطات غير قابلة للتغيير ما لم تُعلَن بالكلمة المفتاحية mut. وبما أن Rust لغة ذات أنواع ثابتة، فإن لكل ارتباط نوعًا معروفًا في وقت الترجمة.
تُعرَّف الارتباطات في الغالب باستخدام الكلمة المفتاحية let. وتحديد نوع الارتباط اختياري في معظم الحالات، لأن استنتاج الأنواع في Rust يستطيع عادةً استنتاج النوع انطلاقًا من القيمة. ويبدو الارتباط هكذا:
// Automatically inferred type
let fingers = 10;
الدوال هي عناصر. فبينما تشير الارتباطات عادةً إلى قيمة معيّنة، تشير العناصر إلى وحدة من تنظيم الكود، غالبًا دالة أو وحدة، وهي متاحة طوال عمر البرنامج. وتُرجع الدالة تلقائيًا نتيجة آخر تعبير فيها. وقد يكون للدالة 0 أو أكثر من المعاملات، وهي ارتباطات يقتصر عمرها على استدعاء الدالة.
استنتاج الأنواع ممكن نظريًا للدوال، لكنه معطّل كخيار مقصود في تصميم اللغة. ورغم أن هذا يعني أنك تحتاج إلى مزيد من الوقت عند كتابة الكود لتحديد أنواع مدخلات الدالة ومخرجاتها بدقة، فإنك توفّر الوقت عند قراءة الكود، لأن جميع أنواع المدخلات والمخرجات معرّفة صراحةً.
fn add(x: i32, y: i32) -> i32 {
x + y
}
يتم استدعاء الدالة بكتابة اسمها متبوعًا بالأقواس الهلالية. وإذا كانت الدالة تحتاج إلى معاملات، فيجب تحديد وسيط لكل معامل داخل الأقواس.
let five = add(2, 3);
إذا تعذّر استنتاج نوع الارتباط، سيُبلغ المترجم عن خطأ. ولإصلاح ذلك، أضف تحديدًا صريحًا لنوع الارتباط.
// Explicit type annotation
let fingers: i32 = 10;
يمكن استخدام العناصر في Rust قبل تعريفها أو بعده، لأن لها عمرًا ساكنًا. أما الارتباطات، فلا يمكن استخدامها إلا بعد تعريفها. واستخدام ارتباط قبل تعريفه يؤدي إلى خطأ في الترجمة.
fn main() {
// `fn add` hasn't yet been defined, but that's perfectly ok
dbg!(add(3, 4));
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
// this won't compile; `a` is used before its binding is defined
let b = a;
let a = x + y;
تستخدم Rust الأقواس المعقوفة ({}) لتعريف نطاق. والارتباط المعرّف داخل نطاق لا يمكنه الخروج منه.
let a = 1;
dbg!(a); // 1
{
// Here, we re-bind `a` to a new value, which is still immutable.
// This technique is called _shadowing_. The new binding is constrained to
// this anonymous scope. Outside this scope, the previous binding still
// applies.
let a = 2;
let b = 3;
dbg!(a, b); // 2, 3
}
// can't use `b` anymore because it is out of scope
// dbg!(b);
// The shadowed `a` in the inner scope above has fallen out of scope,
// leaving us with our original binding.
dbg!(a); // 1
غالبًا ما تُنظَّم عناصر Rust في وحدات. وكل crate هو ضمنيًا وحدة، لكنه يستطيع تعريف وحدات فرعية داخلية بعمق اعتباطي. والوحدة تجمع وظائف مترابطة وتُعرَّف باستخدام الكلمة المفتاحية mod.
mod calc_i32 {
fn add(a: i32, b: i32) -> i32 { a + b }
fn sub(a: i32, b: i32) -> i32 { a - b }
fn mul(a: i32, b: i32) -> i32 { a * b }
fn div(a: i32, b: i32) -> i32 { a / b }
}
تدعم Rust نوعين من التعليقات. الكلمة // تشير إلى تعليق من سطر واحد؛ وكل ما يلي الكلمة حتى نهاية السطر يُتجاهل. والكلمتان /* و*/ تشيران إلى تعليق متعدد الأسطر؛ وكل ما يقع بين هاتين الكلمتين يُتجاهل. ومن الأساليب المألوفة والجيدة تفضيل التعليقات ذات السطر الواحد.
تدعم Rust أيضًا تعليقات التوثيق، التي تظهر في التوثيق المُولَّد الناتج عن cargo doc. وتتكوّن تعليقات التوثيق الخارجية من الكلمة ///، التي تعمل تمامًا كالكلمة //. وهي تنطبق على العنصر الذي يليها، مثل دالة:
/// The `add` function produces the sum of its arguments.
fn add(x: i32, y: i32) -> i32 { x + y }
وتتكوّن تعليقات التوثيق الداخلية من الكلمة //!، التي تعمل تمامًا كالكلمة //. وهي تنطبق على العنصر الذي يحتويها، مثل وحدة:
mod my_cool_module {
//! This module is the bee's knees.
}
يمكن أن تكون تعليقات التوثيق بأي طول وأن تحتوي على markdown، الذي يُعرض في التوثيق المُولَّد.
في هذا التمرين ستكتب بعض الكود لمساعدتك على طهي لازانيا رائعة من كتاب الطبخ المفضل لديك.
لديك أربع مهام، وكلها مرتبطة بالوقت الذي تقضيه في طهي اللازانيا.
عرّف الارتباط expected_minutes_in_oven للتحقق من عدد الدقائق التي ينبغي أن تبقى فيها اللازانيا في الفرن. وفقًا لكتاب الطبخ، الوقت المتوقع في الفرن بالدقائق هو 40:
expected_minutes_in_oven()
// Returns: 40
عرّف الدالة remaining_minutes_in_oven التي تأخذ عدد الدقائق الفعلية التي قضتها اللازانيا في الفرن معاملًا، وتُرجع عدد الدقائق التي ما زالت اللازانيا بحاجة إلى قضائها في الفرن، بناءً على الوقت المتوقع في الفرن بالدقائق من المهمة السابقة.
remaining_minutes_in_oven(30)
// Returns: 10
عرّف الدالة preparation_time_in_minutes التي تأخذ عدد الطبقات التي أضفتها إلى اللازانيا معاملًا، وتُرجع عدد الدقائق التي قضيتها في تحضير اللازانيا، بافتراض أن كل طبقة تستغرق منك 2 دقائق لتحضيرها.
preparation_time_in_minutes(2)
// Returns: 4
عرّف الدالة elapsed_time_in_minutes التي تأخذ معاملين: المعامل الأول هو عدد الطبقات التي أضفتها إلى اللازانيا، والمعامل الثاني هو عدد الدقائق التي قضتها اللازانيا في الفرن. ينبغي أن تُرجع الدالة عدد الدقائق التي عملت فيها على طهي اللازانيا، وهو مجموع وقت التحضير بالدقائق، والوقت بالدقائق الذي قضته اللازانيا في الفرن حتى هذه اللحظة.
elapsed_time_in_minutes(3, 20)
// Returns: 26
سجّل في Exercism لتتعلّم وتتقن Rust عبر 99 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.