27/04/2026 03:20น.

การใช้งาน Borrowing และ References (การยืมข้อมูล) | Rust The Series EP.8
#สอนภาษา Rust
#Rust Borrowing
#References
#Rust
ยินดีต้อนรับเพื่อนๆ ชาว Dev เข้าสู่ Rust The Series ครับ! ใน EP.7 เราได้เห็นความเฮี้ยน (แต่ปลอดภัย) ของกฎ Ownership ไปแล้ว ที่พอย้ายค่า (Move) ปุ๊บ ตัวแปรเดิมก็ตายทันที จนหลายคนอาจจะเริ่มท้อแล้วสงสัยว่า:
"โหยพี่... ถ้าผมแค่จะส่งค่าไปให้ฟังก์ชันอ่านเฉยๆ ผมต้องมานั่ง
.clone()ให้เสีย Memory หรือต้องคอย return ค่ากลับมาคืนเจ้าของเดิมทุกรอบเลยเหรอ?"
คำตอบคือ "ไม่ต้องครับ!" เพราะ Rust มีระบบที่เรียกว่า Borrowing (การยืม) ผ่านสิ่งที่เรียกว่า References (&) ที่จะช่วยให้ชีวิตเราง่ายขึ้นเยอะ
1. การยืมแบบอ่านอย่างเดียว (Immutable References)
การยืมใน Rust เปรียบได้กับการยืมหนังสือจากห้องสมุดครับ:
คุณเอาไปอ่านได้ (Access data)
แต่คุณไม่ใช่เจ้าของ (No Ownership)
และที่สำคัญคือ คุณห้ามขีดเขียนหรือแก้ไขเนื้อหาในหนังสือเล่มนั้นเด็ดขาด!
ในภาษา Rust เราจะใช้เครื่องหมาย & นำหน้าชื่อตัวแปร เพื่อบอกคอมไพเลอร์ว่า "นี่คือการส่งแบบอ้างอิง (Reference) นะ ผมแค่ให้ยืมไปดู ไม่ได้ยกสิทธิ์เจ้าของให้"
Rust
fn main() {
let s1 = String::from("Superdev");
// ส่งแบบ &s1 คือการ "ให้ยืมอ่าน"
let len = calculate_length(&s1);
// ✅ s1 ยังใช้งานได้ปกติ! เพราะสิทธิ์ความเป็นเจ้าของยังอยู่ที่นี่
println!("ความยาวของ '{}' คือ {}", s1, len);
}
fn calculate_length(s: &String) -> usize { // รับพารามิเตอร์เป็น Reference (&)
s.len()
} // พอจบฟังก์ชัน s ซึ่งเป็น "ผู้ยืม" จะหลุด Scope ไป
// แต่ข้อมูลจริงใน Memory ไม่โดนลบ เพราะ s ไม่ใช่เจ้าของตัวจริง
💡 Pro Tip: สังเกตไหมครับว่าตอนเรียกใช้
calculate_length(&s1)เราต้องใส่&และที่ตัวรับในฟังก์ชัน(s: &String)ก็ต้องใส่&เช่นกัน เพื่อเป็นการตกลงกันทั้งคนให้และคนรับว่า "นี่คือการยืมนะ"
2. เมื่ออยากแก้ไข ต้องยืมแบบ Mutable (&mut)
ถ้าการยืมแบบปกติคือการขอยืมไปอ่าน การยืมแบบ Mutable Reference ก็คือการขอยืมไปแก้ไขครับ
เปรียบเหมือนคุณยืมหนังสือจากเพื่อนมา แล้วขออนุญาตเพื่อนว่า "นายๆ เราขอจดโน้ตเพิ่มลงไปในหนังสือหน่อยนะ" ซึ่งเพื่อนจะอนุญาตได้ ก็ต่อเมื่อตัวเพื่อนเอง (เจ้าของ) ยอมให้หนังสือนั้นถูกขีดเขียนได้ตั้งแต่แรก
ใน Rust เราจะใช้เครื่องหมาย &mut แต่มีเงื่อนไขสำคัญคือ: ตัวแปรต้นทางต้องถูกประกาศเป็น mut ไว้ตั้งแต่แรกด้วย
Rust
fn main() {
// 1. ต้นทางต้องเป็น mut ถึงจะให้คนอื่นยืมไปแก้ได้
let mut s = String::from("Hello");
// 2. ตอนส่ง ต้องใส่ &mut เพื่อยืนยันว่า "ให้ยืมไปแก้"
change(&mut s);
println!("{}", s); // ผลลัพธ์จะเป็น "Hello, Superdev"
}
fn change(some_string: &mut String) { // 3. ตัวรับต้องระบุว่าเป็น &mut String
some_string.push_str(", Superdev");
}
⚠️ ข้อควรระวัง: แม้จะยืมไปแก้ได้ แต่ Rust ใจร้ายกว่าเพื่อนคุณครับ เพราะเขากำหนดว่า "ในเวลาเดียวกัน คุณจะให้คนยืมไปแก้ (&mut) ได้แค่คนเดียวเท่านั้น" (ห้ามรุมแก้พร้อมกัน) เดี๋ยวเราจะไปดูเหตุผลกันในหัวข้อถัดไปครับ
3. กฎเหล็กของการยืม (The Rules of Borrowing)
เพื่อให้เกิดความปลอดภัยสูงสุดและป้องกันฝันร้ายของโปรแกรมเมอร์ที่เรียกว่า Data Race (การที่ข้อมูลถูกแก้ไขพร้อมกันจนพัง) Rust จึงตั้งกฎเหล็กที่คอมไพเลอร์จะตรวจยิบ 2 ข้อครับ:
กฎข้อที่ 1: จะอ่านกี่คนก็ได้ แต่ถ้าจะแก้... ต้องแก้คนเดียว
ในเวลาเดียวกัน คุณสามารถถือ Reference ได้เพียง 1 ใน 2 แบบนี้เท่านั้น:
มี "คนยืมอ่าน" (
&) กี่คนก็ได้ (ไม่จำกัดจำนวน) — เหมือนการอ่านวิกิพีเดีย ใครจะอ่านพร้อมกันก็ได้ ข้อมูลไม่เปลี่ยนหรือ มี "คนยืมแก้" (
&mut) ได้เพียง "คนเดียว" เท่านั้น! — และในช่วงที่คนนี้แก้ ห้ามมีคนอื่นแอบอ่านด้วยนะ
กฎข้อที่ 2: Reference ต้องไม่ตายก่อนเจ้าของ (No Dangling References)
คุณจะยืมของจากคนที่หายตัวไปแล้วไม่ได้ ตัวแปรที่ยืมไปใช้จะต้องมั่นใจว่าเจ้าของข้อมูลจริงยังมีชีวิตอยู่ในหน่วยความจำตลอดช่วงเวลาที่ถูกยืม
ลองมาดูตัวอย่างที่คอมไพเลอร์จะด่าเราอย่างแรงครับ:
Rust
fn main() {
let mut s = String::from("hello");
let r1 = &s; // ✅ ยืมอ่าน คนที่ 1 (ผ่าน)
let r2 = &s; // ✅ ยืมอ่าน คนที่ 2 (ผ่าน)
// ❌ ERROR! คอมไพเลอร์จะเบรกทันที
let r3 = &mut s;
println!("{}, {}, and {}", r1, r2, r3);
}
ทำไมถึงไม่ได้?
ลองจินตนาการว่า r1 และ r2 กำลังอ่านเนื้อหาในกระดาษอย่างตั้งใจ แล้วจู่ๆ r3 ก็เดินมาเอาปากกาขีดฆ่าข้อความทิ้งต่อหน้าต่อตา! สิ่งที่ r1 และ r2 อ่านอยู่ก็จะไม่ถูกต้องทันที
Rust เลยตัดไฟแต่ต้นลมว่า: "ถ้ามีคนอ่านอยู่ ห้ามใครมาแก้" และ "ถ้ามีคนแก้ ก็ห้ามคนอื่นอ่าน" เพื่อรับประกันว่าข้อมูลที่คุณถืออยู่ในมือนั้นถูกต้อง 100% เสมอครับ
4. ประโยชน์ของการ Borrowing
หลายคนอาจจะบ่นว่ากฎเยอะจังพี่! แต่เชื่อเถอะครับว่าถ้าคุณผ่านมันไปได้ สิ่งที่คุณจะได้กลับมาคือ Code ที่มีคุณภาพระดับโลก:
🚀 Performance ที่แรงสุดขีด: เพราะเราไม่ต้องเสียเวลาและทรัพยากรไปกับการ Copy หรือ
.clone()ข้อมูลขนาดใหญ่บน Heap Memory ทุกครั้งที่ส่งเข้าฟังก์ชัน การใช้ Reference ก็แค่การส่ง "ที่อยู่" (Pointer) สั้นๆ ซึ่งทำงานได้เร็วมาก🛡️ Safety ระดับสูงสุด: ระบบ Borrow Checker ของคอมไพเลอร์จะตรวจความปลอดภัยให้เราตั้งแต่ตอนเขียน ไม่ต้องรอไปลุ้นให้โปรแกรม Crash ตอนรัน (Runtime) มั่นใจได้ว่าไม่มีใครแอบแก้ข้อมูลตัดหน้ากันแน่นอน
💎 Clean Code & Better DX: โค้ดของคุณจะอ่านง่ายและเป็นธรรมชาติมากขึ้น ไม่ต้องเขียนฟังก์ชันแปลกๆ ที่ต้องคอย return ค่าเดิมกลับมาเพียงเพื่อรักษา Ownership ให้วุ่นวาย
สรุป
ระบบ Borrowing คือหัวใจที่ทำให้ Rust ใช้งานได้จริงและทรงพลังครับ แม้กฎจะดูจุกจิกในช่วงแรก แต่ถ้าคุณเริ่มจับจังหวะได้ว่า "ใครคือเจ้าของ" และ "ใครเป็นแค่คนยืม" คุณจะพบว่าตัวเองกำลังเขียนโปรแกรมที่เร็วระดับเทพ ปลอดภัยจากการจารกรรมข้อมูลใน Memory และที่สำคัญคือ "Memory ไม่รั่วเลยแม้แต่ไบต์เดียว" โดยไม่ต้องง้อ Garbage Collector เลยครับ!
📌 ใน EP. ถัดไป (EP.9): เราจะไปลุยกันต่อกับเรื่อง Slices ซึ่งเป็นการยืมตข้อมูลเพียงบางส่วนมาใช้งาน (เช่น จะเอาแค่คำแรกในประโยคยาวๆ ต้องทำยังไง?) เรื่องนี้จะช่วยให้คุณจัดการ Array และ String ได้แบบโปรเฟสชันนอลยิ่งขึ้น... แล้วเจอกันครับ 🦀✨
🎯 ติดตามความรู้สาย Dev แบบสุดจัดได้ที่: ไม่อยากพลาดบทความเทคนิคเชิงลึกและอัปเดตใหม่ๆ จากทีมงาน Superdev Academy ติดตามเราได้ทุกช่องทางที่นี่ครับ:
🔵 Facebook: Superdev Academy Thailand (อัปเดตข่าวสารและบทความใหม่)
🎬 YouTube: Superdev Academy Channel (ติวเข้มแบบวิดีโอ)
📸 Instagram: @superdevacademy (เกร็ดความรู้สั้นๆ และเบื้องหลังการทำงาน)
🎬 TikTok: @superdevacademy (Tips & Tricks ฉบับย่อยง่าย)
🌐 Website: superdevacademy.com (คลังบทความและคอร์สเรียนฉบับเต็ม)