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

Move vs Copy

เส้นแบ่งที่เลือนลางของ JavaScript ระหว่าง value และ reference

หัวข้อที่มีชื่อว่า “เส้นแบ่งที่เลือนลางของ JavaScript ระหว่าง value และ reference”

ใน JavaScript, primitive (number, boolean, string) ถูกส่ง by value — การ copy ราคาถูกและอัตโนมัติ Object และ array ถูกส่ง by reference — ทั้งสองตัวแปรชี้ไปที่ heap data เดียวกัน

TypeScript สะท้อนเรื่องนี้ผ่าน type system แต่ไม่เปิดให้คุณควบคุม คุณทำให้ type ของตัวเองทำงานเหมือน primitive ไม่ได้

Rust ชัดเจน: type ไม่ implement Copy trait (และถูก duplicate อัตโนมัติเมื่อ assign) ก็จะ follow move semantics (ownership โอน) คุณสามารถ derive Clone สำหรับ explicit deep copy ได้ด้วย

Copy type อยู่บน stack และ duplicate ได้ถูกมาก การ assign หรือส่งเข้า function จะได้ copy ที่เป็นอิสระเต็มตัว โดยไม่ต้องเขียน syntax พิเศษ

TypeScript
// TypeScript — primitive copy อัตโนมัติ (เหมือน Rust Copy)
let a = 42;
let b = a; // b เป็น copy อิสระ
b = 100;
console.log(a); // 42 — a ไม่เปลี่ยน
// แต่ TypeScript ไม่มีวิธีให้ struct ทำงานแบบนี้:
const p1 = { x: 1, y: 2 };
const p2 = p1; // p2 เป็น reference — share object เดียวกัน
p2.x = 99;
console.log(p1.x); // 99 — p1 ถูก mutate ผ่าน p2
Rust
fn main() {
// i32, f64, bool, char ล้วนเป็น Copy
let a: i32 = 42;
let b = a; // copied — a ยังใช้ได้
println!("a={} b={}", a, b);
// Tuple ของ Copy type ก็เป็น Copy
let t1 = (1, 2.0, true);
let t2 = t1;
println!("t1={:?} t2={:?}", t1, t2);
}

Type อย่าง String และ Vec<T> เป็น owner ของ heap-allocated data การ assign จึงเป็นการ move ownership ถ้าอยากได้ copy อิสระสองชุด ต้องเรียก .clone() เอง

TypeScript
// TypeScript — string เป็น primitive copy อัตโนมัติ
let s1 = "hello";
let s2 = s1;
console.log(s1, s2); // ทั้งคู่ใช้ได้ — string เป็น primitive ใน JS
// Object ต้องใช้ spread สำหรับ shallow copy
const obj1 = { items: [1, 2, 3] };
const obj2 = { ...obj1 }; // shallow clone
const obj3 = structuredClone(obj1); // deep clone (ES2022)
console.log(obj1.items, obj2.items);
Rust
#[derive(Debug, Clone)]
struct Point {
x: f64,
y: f64,
}
fn main() {
// String — heap value ใช้ move semantics
let s1 = String::from("hello");
let s2 = s1.clone(); // explicit deep copy
println!("s1={} s2={}", s1, s2); // ทั้งคู่ใช้ได้
// struct ของคุณ — derive Clone เพื่อใช้ .clone()
let p1 = Point { x: 1.0, y: 2.0 };
let p2 = p1.clone();
println!("p1={:?} p2={:?}", p1, p2);
// ถ้าไม่มี Clone การ assign จะ move ownership:
let p3 = Point { x: 3.0, y: 4.0 };
let p4 = p3; // p3 ถูก move — p3 ใช้ไม่ได้แล้ว
println!("p4={:?}", p4);
}
#[derive(Debug, Clone)]
struct Point {
x: f64,
y: f64,
}
fn main() {
let a: i32 = 42;
let b = a;
println!("a={} b={} (both valid, i32 is Copy)", a, b);
let p1 = Point { x: 1.0, y: 2.0 };
let p2 = p1.clone();
println!("p1={:?} p2={:?}", p1, p2);
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1={} s2={}", s1, s2);
}
Type ไหนที่ implement `Copy` trait?
วิธี idiomatic ในการสร้าง copy อิสระของ `String` ใน Rust คืออะไร?
ทำไม `String` ถึงไม่ implement `Copy`?