References และ Borrowing
Borrow แทนที่จะ Move
หัวข้อที่มีชื่อว่า “Borrow แทนที่จะ Move”การ move ค่าเข้าไปในฟังก์ชันมักไม่จำเป็น — คุณแค่อยากให้ฟังก์ชันอ่านค่า ไม่ได้อยากยกความเป็นเจ้าของให้ Rust แก้ปัญหานี้ด้วย references reference ช่วยให้คุณส่งค่าเข้าไปในฟังก์ชันได้โดยไม่ต้องสละ ownership
syntax &T หมายถึง “shared reference ไปยังค่าของ type T” การสร้าง reference เรียกว่า borrowing
fn calculate_length(s: &String) -> usize { s.len()} // s goes out of scope, but since it does not own the data, nothing is dropped
fn main() { let s = String::from("hello"); let len = calculate_length(&s); // pass a reference, not the value println!("{} has {} characters", s, len); // s is still valid}syntax &s สร้าง reference ไปยัง s ส่วน signature ของฟังก์ชัน s: &String ประกาศว่าพารามิเตอร์นี้เป็น reference ไม่ใช่ String ที่เป็นเจ้าของค่า
References ไม่ได้เป็นเจ้าของ
หัวข้อที่มีชื่อว่า “References ไม่ได้เป็นเจ้าของ”เพราะ reference ไม่ได้เป็นเจ้าของค่าที่ชี้ไป ค่านั้นจึง ไม่ถูก dropped เมื่อ reference ออกจาก scope ownership ยังคงอยู่กับตัวแปรเดิม
fn print_greeting(name: &String) { println!("Hello, {}!", name);} // reference dropped here — name itself is unaffected
fn main() { let name = String::from("Alice"); print_greeting(&name); print_greeting(&name); // can borrow again — we still own name println!("Still have: {}", name);}Shared References หลายตัว
หัวข้อที่มีชื่อว่า “Shared References หลายตัว”คุณสามารถมี shared reference (&T) ไปยังค่าหนึ่ง จำนวนเท่าไรก็ได้ พร้อม ๆ กัน ตราบใดที่ไม่มีตัวใดเป็น mutable reference เลย shared reference เป็นแบบ read-only
fn main() { let s = String::from("shared"); let r1 = &s; let r2 = &s; let r3 = &s; println!("{} {} {}", r1, r2, r3); // all three are valid simultaneously}References กับ Signature ของฟังก์ชัน
หัวข้อที่มีชื่อว่า “References กับ Signature ของฟังก์ชัน”เมื่อพารามิเตอร์ของฟังก์ชันเป็น &String ผู้เรียกจะส่ง &my_string เข้าไป เมื่อพารามิเตอร์เป็น &str (string slice) ฟังก์ชันจะยืดหยุ่นกว่า — รับได้ทั้ง &String และ string literal โดยทั่วไปควรเลือกใช้ &str แทน &String สำหรับพารามิเตอร์ของฟังก์ชัน
fn greet(name: &str) { println!("Hello, {}!", name);}
fn main() { let owned = String::from("Bob"); greet(&owned); // &String coerces to &str greet("Charlie"); // string literal is already &str}fn calculate_length(s: &String) -> usize { s.len()}
fn greet(name: &str) { println!("Hello, {}!", name);}
fn main() { let s = String::from("hello");
// Pass a reference — s is not moved let len = calculate_length(&s); println!("length of {} is {}", s, len);
// Multiple shared borrows are allowed let r1 = &s; let r2 = &s; println!("r1={} r2={}", r1, r2);
// &String coerces to &str let owned = String::from("Alice"); greet(&owned); // borrow, not move greet("Bob"); // string literal println!("owned is still: {}", owned);}Compiling…