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

Ownership

ใน JavaScript และ TypeScript garbage collector คอย track ทุก heap value (string, array, object) ให้เอง คุณสร้าง value ได้อย่างอิสระ แล้ว GC จะดูให้ว่าเมื่อไหร่ไม่มีใครใช้แล้วค่อยคืน memory ไม่ต้องเรียก free() เอง และไม่ต้องกังวลเรื่อง use-after-free

Rust ไม่มี garbage collector แต่มี ownership: ระบบกฎ compile-time ที่ให้ทุก value มี owner แค่คนเดียว เมื่อ owner หลุด scope value จะถูกคืน memory อัตโนมัติ — ไม่ต้องการ GC

ใน TypeScript การ assign object ไปให้ตัวแปรใหม่สร้าง reference ที่สอง ตัวแปรทั้งสองชี้ไปที่ data เดียวกัน ใน Rust การ assign heap value move ownership: ตัวแปรเดิมจะใช้ไม่ได้แล้ว

TypeScript
// TypeScript — สอง reference, object เดียวกัน
const a = { name: "Alice" };
const b = a; // b ชี้ไปที่ object เดียวกัน
console.log(a.name); // "Alice" — a ยังใช้ได้
console.log(b.name); // "Alice" — ทั้งคู่ทำงาน
// GC จะคืน object เมื่อ a และ b ทั้งคู่หลุด scope
// คุณควบคุมเวลาไม่ได้
Rust
fn main() {
// Rust — String เป็น heap value
let a = String::from("Alice");
let b = a; // ownership MOVES จาก a ไป b
// println!("{}", a); // error[E0382]: use of moved value: `a`
println!("{}", b); // ใช้ได้แค่ b
// เมื่อ b หลุด scope ปลาย main()
// Rust คืน String data อัตโนมัติ ไม่ต้องการ GC
}

การส่ง heap value เข้า function จะ move ค่านั้นเข้าไปด้วย ฝั่ง caller จึงใช้ค่าเดิมต่อไม่ได้ เว้นแต่ function จะ return กลับมาให้

TypeScript
// TypeScript — ส่ง object ไม่ได้ move ownership
function greet(name: string) {
console.log(`Hello, ${name}`);
}
const s = "world";
greet(s);
console.log(s); // ยังใช้ได้ — JS ส่ง reference สำหรับ object
Rust
fn greet(name: String) {
// name เป็น owner ที่นี่
println!("Hello, {}", name);
} // name ถูก drop ที่นี่
fn main() {
let s = String::from("world");
greet(s); // ownership move เข้าไปใน greet()
// println!("{}", s); // error[E0382]: use of moved value: `s`
}
fn takes_ownership(s: String) {
println!("got: {}", s);
} // s dropped here
fn makes_copy(n: i32) {
println!("copy: {}", n);
} // n dropped here, but i32 is Copy so the caller's copy is unaffected
fn main() {
let s = String::from("hello");
takes_ownership(s);
// println!("{}", s); // would be a compile error — s was moved
let x = 5;
makes_copy(x);
println!("x is still valid: {}", x); // fine — i32 is Copy
}
เกิดอะไรขึ้นเมื่อคุณ assign `String` ให้กับตัวแปรใหม่ใน Rust?
Heap value ถูกคืน memory เมื่อไหร่ใน Rust?
ต้องทำอย่างไรถึงจะใช้ `String` ใน function แล้วยังใช้ค่าเดิมต่อใน caller ได้?
ข้อใดไม่ใช่กฎสามข้อของ ownership ใน Rust?