ข้ามไปยังเนื้อหา

Borrowing & References

ใน TypeScript การส่ง object ไปให้ function ส่ง reference ให้ ทั้ง caller และ callee สามารถอ่านและเขียน object พร้อมกันได้ ภาษาไม่มีข้อจำกัดว่ามี reference กี่ตัวหรือทำอะไรได้บ้าง

Borrow checker ของ Rust บังคับใช้กฎเข้มงวดเกี่ยวกับ reference ตั้งแต่ compile time กฎเหล่านี้ป้องกัน data race, dangling pointer, และ use-after-free — ทั้งหมดโดยไม่มีต้นทุน runtime

Shared reference (&T) ให้คุณอ่าน value โดยไม่รับ ownership สามารถมี shared reference ได้หลายตัวพร้อมกัน

TypeScript
// TypeScript — ส่ง reference แค่นั้น (ไม่มีกฎ)
function getLength(s: string): number {
return s.length;
}
const greeting = "hello";
const len = getLength(greeting);
console.log(greeting, len); // ทั้งคู่ยังใช้ได้
Rust
fn get_length(s: &String) -> usize {
s.len() // เรา borrow s — ไม่สามารถ move ออกจากมัน
}
fn main() {
let greeting = String::from("hello");
let len = get_length(&greeting); // ยืม greeting ให้ function
println!("{} has {} chars", greeting, len);
// greeting ยังใช้ได้ — เราแค่ยืมมัน
}

Mutable reference (&mut T) ให้คุณทั้งอ่านและแก้ไข value แต่ Rust มีกฎ exclusive: ตราบใดที่ &mut reference ยังอยู่ ห้ามมี reference อื่นใด — ไม่ว่า shared หรือ mutable — พร้อมกัน

TypeScript
// TypeScript — ไม่มีข้อจำกัดสำหรับ read + write พร้อมกัน
function appendWorld(s: { value: string }): void {
s.value += ", world";
}
const msg = { value: "hello" };
appendWorld(msg);
console.log(msg.value); // "hello, world"
Rust
fn append_world(s: &mut String) {
s.push_str(", world");
}
fn main() {
let mut s = String::from("hello");
append_world(&mut s);
println!("{}", s); // "hello, world"
// หลาย shared ref ใช้ได้ — ไม่มีการ mutate
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
}

นี่คือ error ที่พบบ่อยที่สุดสำหรับ Rust developer มือใหม่ โค้ดด้านล่างพยายาม hold shared reference และ mutable reference พร้อมกัน:

fn main() {
let mut s = String::from("hello");
let r1 = &s; // shared borrow เริ่ม
let r2 = &s; // shared borrow อีกตัว — ยังโอเค
let r3 = &mut s; // ERROR: cannot borrow `s` as mutable because it is also borrowed as immutable
println!("{}, {}, {}", r1, r2, r3);
}
// error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
// --> src/main.rs:6:14
// |
// 4 | let r1 = &s;
// | -- immutable borrow occurs here
// 6 | let r3 = &mut s;
// | ^^^^^^ mutable borrow occurs here
// 7 | println!("{}, {}, {}", r1, r2, r3);
// | -- immutable borrow later used here

การแก้ไขง่าย: ทำให้แน่ใจว่า shared และ mutable borrow ไม่ overlap กัน ให้ shared borrow จบก่อน (จบเมื่อถูกใช้ครั้งสุดท้าย) แล้วค่อย take mutable borrow:

fn append_world(s: &mut String) {
s.push_str(", world");
}
fn main() {
let mut s = String::from("hello");
append_world(&mut s);
println!("{}", s);
// multiple shared refs are fine
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
}
Mutable reference (`&mut T`) ไปยัง value เดียวกันมีได้กี่ตัวพร้อมกันใน Rust?
`&T` ใน function signature หมายความว่าอะไร?
กฎ borrow checker ข้อใดป้องกัน data race ตั้งแต่ compile time?