דילוג לתוכן המרכזי
מודול 3 · שיעור 2 מתוך 26/14 בקורס~15 min
שיעורי מודול (2/2)

הפניות והשאלה

ב-Rust, העברת בעלות הלוך ושוב לפונקציות יכולה להיות מייגעת. כדי לפתור זאת, 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:

Rust
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 אוכפת שני כללים בסיסיים:

  1. ניתן לקבל כל מספר של הפניות בלתי ניתנות לשינוי (&T) לערך בו-זמנית.
  2. או שאתה יכול לקבל הפניה אחת הניתנת לשינוי (&mut T) לערך בכל פעם.

אתה בהחלט לא יכול לערבב הפניות בלתי ניתנות לשינוי ושינוי עבור אותו ערך באותו היקף:

Rust
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): ההיקף של הפניה מסתיים בשורה האחרונה שבה נעשה שימוש בפועל, לא בהכרח בסוף הבלוק.

זה הופך את הקוד הבא לתקף לחלוטין:

Rust
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

נסה זאת בעצמך

פעילות גופנית#rust.m3.l2.e1
ניסיונות: 0טוען...

העבר הפניה בלתי ניתנת לשינוי של s1 לפונקציה calculate_length באמצעות הסמל &.

טוען עורך...
הצג רמז

החלף `/* TODO \_/`ב`&s1` כדי להעביר הפניה בלתי ניתנת לשינוי למחרוזת.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#rust.m3.l2.e2
ניסיונות: 0טוען...

הפוך את המשתנה s למשתנה (תן mut s) והעבר הפניה ניתנת לשינוי (&mut s) לפונקציית השינוי כדי לאפשר לה לשנות את המחרוזת.

טוען עורך...
הצג רמז

השתמש ב-`let mut s`במקום `let s`and call`change(&mut s);`.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#rust.m3.l2.e3
ניסיונות: 0טוען...

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 ניסיונות