دروس الوحدة (2/2)
المراجع والاقتراض
في Rust، قد يكون نقل الملكية إلى الوظائف ذهابًا وإيابًا أمرًا شاقًا. لحل هذه المشكلة، يستخدم Rust المراجع (&).
يُسمى إنشاء مرجع لقيمة الاقتراض.
المراجع غير القابلة للتغيير
يتم الإعلان عن المرجع عن طريق وضع بادئة للنوع أو المتغير بالرمز &. بشكل افتراضي، تكون المراجع غير قابلة للتغيير: فهي تسمح بقراءة القيمة ولكن لا تسمح بتعديلها.
fn main() {
let s1 = String::from("hello");
// We pass a reference to s1, not ownership
let len = calculate_length(&s1);
// s1 is still usable here!
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len()
} // Here, s goes out of scope, but since it doesn't own the value, nothing happensالمراجع القابلة للتغيير
إذا كنت بحاجة إلى تعديل قيمة مستعارة، فيجب عليك استخدام مرجع قابل للتغيير مع &mut. يجب أيضًا تعريف المتغير الأصلي بأنه قابل للتغيير باستخدام mut:
fn main() {
let mut s = String::from("hello");
// We pass a mutable reference
change(&mut s);
println!("{}", s); // Prints "hello, world"
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}قواعد الاقتراض
لمنع تلف الذاكرة وسباق البيانات في وقت الترجمة، يفرض Rust قاعدتين أساسيتين:
- يمكنك الحصول على أي عدد من المراجع غير القابلة للتغيير (
&T) لقيمة ما في نفس الوقت. - أو يمكن أن يكون لديك مرجع واحد قابل للتغيير (
&mut T) لقيمة ما في المرة الواحدة.
لا يمكنك مطلقًا الجمع بين المراجع غير القابلة للتغيير والمتغيرة لنفس القيمة في نفس النطاق:
let mut s = String::from("hello");
let r1 = &s; // Valid
let r2 = &s; // Valid
// let r3 = &mut s; // COMPILATION ERROR! You cannot create &mut s if s is already borrowed as immutableالنطاق المرجعي ومدة الحياة غير المعجمية (NLL)
تاريخيًا، استمر نطاق المرجع حتى نهاية الكتلة التي تم إنشاؤه فيها. اليوم، أصبح مترجم Rust أكثر ذكاءً بفضل Non-Lexical Lifetimes (NLL): ينتهي نطاق المرجع عند السطر الأخير الذي يتم استخدامه فيه بالفعل، وليس بالضرورة في نهاية الكتلة.
وهذا يجعل الكود التالي صالحًا تمامًا:
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // Last use of r1 and r2. The immutable references expire here!
let r3 = &mut s; // Valid! No active immutable references exist at this pointجربه بنفسك
قم بتمرير مرجع غير قابل للتغيير لـ s1 إلى دالة Calc_length باستخدام الرمز &.
إظهار التلميح
استبدل `/* TODO \_/`بـ`&s1` لتمرير مرجع غير قابل للتغيير إلى السلسلة.
الحل متاح بعد 3 من المحاولات
اجعل المتغير s قابلاً للتغيير (let mut s) وقم بتمرير مرجع قابل للتغيير (&mut s) إلى دالة التغيير للسماح لها بتعديل السلسلة.
إظهار التلميح
استخدم `let mut s` بدلاً من`let s`and call`change(&mut s);`.
الحل متاح بعد 3 من المحاولات
Declare a variable s containing String::from("Rust"). Create two distinct immutable references r1 and r2 to s, and finally print both references separated by a space using the println! macro.
إظهار التلميح
Assign `let r1 = &s;` and `let r2 = &s;` to obtain two immutable references, then print them with `println!("{} {}", r1, r2);`.
الحل متاح بعد 3 من المحاولات