Lifetimes
TypeScript ไม่มี concept นี้เลย
หัวข้อที่มีชื่อว่า “TypeScript ไม่มี concept นี้เลย”TypeScript ไม่มี concept ของ lifetime เลย เมื่อคุณ hold reference ไปที่ object GC ยัง keep object นั้นไว้ตราบเท่าที่ reference ยังมีอยู่ คุณไม่ต้องคิดเลยว่า reference ยังถูกต้องอยู่ไหม
Rust ไม่มี garbage collector จึงต้องพิสูจน์ตั้งแต่ compile time ว่าทุก reference ยังใช้งานได้จริงตลอดช่วงที่ถูกใช้ ระบบการพิสูจน์นี้เรียกว่า lifetime
ทำไมถึงต้องมี lifetime — ปัญหา dangling reference
หัวข้อที่มีชื่อว่า “ทำไมถึงต้องมี lifetime — ปัญหา dangling reference”TypeScript ไม่มี dangling reference เลย — GC จะไม่ยอมคืน underlying data ตราบใดที่ยังมี reference ชี้อยู่ ส่วน Rust คืน data ทันทีที่ owner หลุด scope ถ้าไม่มี lifetime ก็เป็นไปได้ที่จะ return reference ไปยัง data ที่ถูกคืนไปแล้ว:
// โค้ดนี้ compile ไม่ได้ — และนั่นคือจุดประสงค์fn dangle() -> &String { let s = String::from("hello"); &s // error[E0106]: missing lifetime specifier // แม้ระบุ lifetime แล้ว ก็ยังล้มเหลว: // s ถูก drop เมื่อ function จบ — reference จะ dangle!}// error[E0515]: cannot return reference to local variable `s`// --> src/main.rs:3:5// |// 3 | &s// | ^^ returns a reference to data owned by the current functionCompiler จับได้ ไม่มีการป้องกันเทียบเท่าใน TypeScript เพราะ GC ป้องกันสถานการณ์นั้นอยู่แล้ว แต่แลกกับ runtime overhead
Lifetime annotation บน function
หัวข้อที่มีชื่อว่า “Lifetime annotation บน function”เมื่อ function return reference ที่ derive มาจาก input compiler ต้องรู้ว่า output lifetime ผูกกับ input ตัวไหน คุณ annotate ด้วย 'a:
// TypeScript — ไม่ต้องการ lifetime conceptfunction longest(x: string, y: string): string { return x.length >= y.length ? x : y;}
const result = longest("long string", "xyz");console.log(result); // "long string"// TypeScript ไม่กังวลว่า returned string// จะมีชีวิตยาวกว่า input ไหม GC จัดการ// 'a คือ lifetime parameter — มันบอกว่า:// "output มีชีวิตนานอย่างน้อยเท่ากับ input ทั้งคู่"fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() >= y.len() { x } else { y }}
fn main() { let s1 = String::from("long string"); let result; { let s2 = String::from("xyz"); result = longest(s1.as_str(), s2.as_str()); println!("longest: {}", result); // result ต้องใช้ก่อน s2 ถูก drop }}Lifetime ใน struct
หัวข้อที่มีชื่อว่า “Lifetime ใน struct”ถ้า struct hold reference ไว้ ต้องประกาศ lifetime เพื่อบอกว่า “struct นี้อยู่ได้ไม่นานกว่า data ที่ reference ถึง”:
// TypeScript — struct ที่ hold reference เป็นแค่ object propertyinterface ImportantExcerpt { part: string; // แค่ string — GC เก็บไว้นานเท่าที่ต้องการ}
const text = "Call me Ishmael. Some years ago...";const excerpt: ImportantExcerpt = { part: text.split(".")[0] };console.log(excerpt.part);// Struct hold reference ไม่ใช่ owned data// 'a บอกว่า: ImportantExcerpt อยู่ได้ไม่นานกว่า &str ที่มัน referencestruct ImportantExcerpt<'a> { part: &'a str,}
fn main() { let novel = String::from("Call me Ishmael. Some years ago..."); let first_sentence = novel.split('.').next().expect("no period"); let excerpt = ImportantExcerpt { part: first_sentence }; println!("{}", excerpt.part); // novel ยังมีชีวิตอยู่ที่นี่ ดังนั้น reference ใน excerpt ยังถูกต้อง}ลองเขียนเอง
หัวข้อที่มีชื่อว่า “ลองเขียนเอง”fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}
fn main() { let s1 = String::from("long string"); let result; { let s2 = String::from("xyz"); result = longest(s1.as_str(), s2.as_str()); println!("longest: {}", result); }}Compiling…