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

כללי הבעלות

בעלות היא התכונה הייחודית ביותר של חלודה. זה מאפשר לשפה להבטיח בטיחות זיכרון מבלי להזדקק לאספן אשפה או לאלץ אותך להקצות זיכרון ערימה באופן ידני (כמו ב-C או C++).

שלושת כללי הבעלות

ניהול הזיכרון ב-Rust נשלט על ידי שלושה כללים פשוטים שנבדקו בקפדנות על ידי המהדר:

  1. לכל ערך ב-Rust יש משתנה שנקרא הבעלים שלו.
  2. יכול להיות רק בעלים אחד בכל פעם.
  3. כשהבעלים יוצא מהתחום, הערך ירד אוטומטית.

סטאק נגד ערימה

כדי להבין בעלות, חשוב לדעת היכן נמצאים הנתונים:

  • מחסנית: מאחסן נתונים בגודל קבוע הידוע בזמן ההידור (למשל, מספרים שלמים, בוליאנים). הגישה מהירה במיוחד.
  • ערימה: מאחסן נתונים בגודל דינמי לא ידוע בזמן ההידור (למשל, String). ההקצאה איטית יותר ודורשת מצביע המאוחסן ב-Stack.

הרעיון של "זוז"

כאשר אנו מקצים משתנה שהוקצה ערימה לאחר, Rust מזיז (או מעביר) בעלות על הערך, ומבטל את התוקף של המשתנה הראשון:

Rust
let s1 = String::from("ciao");
let s2 = s1; // Ownership of the text moves to s2. s1 is NO longer usable!

// println!("{}", s1); // COMPILATION ERROR! s1 is "borrow of moved value"
println!("{}", s2); // Valid!

התנהגות זו מונעת את "שגיאת הפנוי הכפולה" (ניסיון לשחרר את אותו זיכרון פעמיים כאשר יוצאים מהתחום), מכיוון שרק s2 יפנה את הזיכרון.

הרעיון של "כפול" (עתק עמוק)

אם אנחנו צריכים במפורש להעתיק את כל התוכן של String (הן מצביעי הערימה והן נתוני הטקסט בפועל בערימה), נוכל להשתמש בשיטת .clone(). זה משכפל לחלוטין את הנתונים בערימה, תוך שמירה על תוקף המשתנה המקורי והחדש, במחיר של תקורה של ביצועים עבור הקצאת הזיכרון החדשה:

Rust
let s1 = String::from("ciao");
let s2 = s1.clone(); // Deep copy. Both variables remain valid!
println!("s1: {}, s2: {}", s1, s2);

המושג "העתק"

עבור טיפוסים פשוטים המאוחסנים במלואם במחסנית (כמו מספרים שלמים i32, בוליאנים bool, תווים char), ההקצאה מבצעת עותק רדוד אוטומטי בפועל, כלומר שני המשתנים נשארים תקפים:

Rust
let x = 5;
let y = x; // Copies the value 5 onto the stack. Both variables are usable!
println!("x: {}, y: {}", x, y); // Valid!

נסה זאת בעצמך

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

הכריז על מחרוזת s1 המכילה את הטקסט 'שלום'. הקצה s1 ל- s2 (כדי להעביר בעלות). לבסוף, הדפס s2 באמצעות println!.

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

השתמש ב-`let s2 = s1;` כדי להעביר בעלות ל-`s2` והדפיס אותו עם `println!('{}', s2);`.

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

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

הכריז על משתנה שלם x עם ערך של 5. הקצה x ל-y (ביצוע העתקה). לבסוף, הדפס גם x וגם y באותו println! הַצהָרָה.

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

עשה `תן y = x;` ולאחר מכן הדפס את שני הערכים, למשל, `println!('{} {}', x, y);`.

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

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

Declare a String s1 with the value "Rust". Create a deep copy of s1 in a new variable s2 using the clone method. Finally, print both s1 and s2 separated by a space using the println! macro.

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

Use `let s2 = s1.clone();` to deep copy the value of `s1` into `s2`, then print them with `println!("{} {}", s1, s2);`.

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