Ownership และ Moves
เจ้าของได้ทีละหนึ่ง
หัวข้อที่มีชื่อว่า “เจ้าของได้ทีละหนึ่ง”ทุกค่าใน Rust มีเจ้าของเพียงหนึ่งเดียว เมื่อคุณ assign ค่าให้ตัวแปรอีกตัว หรือส่งค่านั้นเข้าไปในฟังก์ชัน สิ่งที่เกิดขึ้นขึ้นอยู่กับว่า type นั้น implement Copy หรือไม่
Type ที่ไม่ใช่ Copy จะ Move
หัวข้อที่มีชื่อว่า “Type ที่ไม่ใช่ Copy จะ Move”Type ที่เป็นเจ้าของหน่วยความจำบน heap — อย่างเช่น String, Vec<i32> หรือ Box<i32> — จะ ไม่ implement Copy เมื่อคุณ assign ตัวหนึ่งไปยังอีกตัวแปรหนึ่ง ค่านั้นจะถูก moved: binding เดิมจะใช้งานไม่ได้
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 is moved into s2
// println!("{}", s1); // ERROR: s1 was moved println!("{}", s2); // fine}กฎเดียวกันนี้ใช้เมื่อคุณส่งค่าเข้าไปในฟังก์ชัน:
fn consume(s: String) { println!("{}", s);} // s is dropped here
fn main() { let name = String::from("Rust"); consume(name); // name is moved // name is no longer valid here}Type ที่เป็น Copy จะถูกทำซ้ำ
หัวข้อที่มีชื่อว่า “Type ที่เป็น Copy จะถูกทำซ้ำ”Type แบบ scalar ง่าย ๆ ที่เก็บอยู่บน stack ทั้งหมด — จำนวนเต็ม, bool, char, ตัวเลขทศนิยม และ tuple ของสิ่งเหล่านี้ — จะ implement Copy การ assign หรือส่งต่อค่าเหล่านี้จะทำ copy แบบ bitwise; ตัวเดิมยังใช้งานได้
fn main() { let x: i32 = 42; let y = x; // x is COPIED, not moved println!("x={} y={}", x, y); // both valid}Type ที่เป็น Copy ที่พบบ่อย: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, char
Deep Copy แบบชัดเจนด้วย .clone()
หัวข้อที่มีชื่อว่า “Deep Copy แบบชัดเจนด้วย .clone()”เมื่อคุณต้องการ copy แบบอิสระเต็มรูปแบบของค่าที่เป็นเจ้าของหน่วยความจำบน heap ให้เรียก .clone() นี่คือการเลือกทำ (opt-in) อย่างชัดเจนต่อการดำเนินการที่อาจมีค่าใช้จ่ายสูง
fn main() { let original = String::from("keep me"); let copy = original.clone(); // deep copy println!("original={} copy={}", original, copy);}การคืน Ownership
หัวข้อที่มีชื่อว่า “การคืน Ownership”ฟังก์ชันสามารถคืน ownership กลับไปให้ผู้เรียกได้ด้วยการ return ค่านั้นออกมา:
fn take_and_give_back(s: String) -> String { s // ownership moves out of the function}
fn main() { let s1 = String::from("hello"); let s2 = take_and_give_back(s1); println!("{}", s2);}วิธีนี้ใช้ได้แต่ยืดยาว ในทางปฏิบัติคุณจะเลือกใช้ borrowing (บทเรียนถัดไป) แทนการ move-แล้ว-return เกือบทุกครั้ง
fn take_ownership(s: String) -> String { println!("inside take_ownership: {}", s); s // return ownership to caller}
fn main() { // String is NOT Copy — it moves let s1 = String::from("hello"); let s2 = take_ownership(s1); // s1 is moved println!("s2 now owns: {}", s2);
// i32 IS Copy — it is copied let x = 42; let y = x; println!("x={} y={}", x, y);
// .clone() makes an explicit deep copy let original = String::from("keep me"); let cloned = original.clone(); println!("original={} cloned={}", original, cloned);}Compiling…