28/04/2026 04:40น.

การใช้งาน Slices เพื่อจัดการข้อมูลบางส่วนแบบ Zero-Copy | Rust The Series EP.9
#สอนภาษา Rust
#Rust
#String Slice
#Array Slice
#Slices
ยินดีต้อนรับกลับสู่ Rust The Series ครับ! จาก EP.8 ที่เราได้รู้จักการยืม (Borrowing) ข้อมูลแบบทั้งก้อนไปแล้ว วันนี้เราจะมาแอดวานซ์ขึ้นอีกนิด กับสถานการณ์ที่เราไม่ได้ต้องการข้อมูลทั้งหมด แต่ต้องการแค่บางส่วน ของมันมาใช้งานครับ ลองจินตนาการว่าเรามีข้อความยาวๆ อย่าง "Superdev Academy" แต่อยากได้แค่คำว่า "Superdev" มาประมวลผลต่อล่ะ?
ในภาษาทั่วไป: เราอาจต้องสั่งตัดคำ (Substring) แล้วสร้างตัวแปรใหม่ขึ้นมา ซึ่งหมายถึงการจอง Memory เพิ่มเพื่อเก็บข้อมูลชุดเดิมซ้ำอีกรอบ
ในภาษา Rust: เรามีอาวุธที่เรียกว่า Slice ที่ช่วยให้เราหยิบเฉพาะส่วนที่ต้องการมาใช้ได้ทันที โดยไม่ต้องคัดลอกข้อมูลใหม่แม้แต่ไบต์เดียว!
1. Slice คืออะไร?
ถ้าจะอธิบายให้เห็นภาพที่สุด Slice คือการสร้างหน้าต่างเล็กๆ เพื่อส่องดูข้อมูลแค่บางช่วงใน Collection ขนาดใหญ่ (เช่น String หรือ Array) ครับ
ในเชิงเทคนิค Slice เป็นข้อมูลประเภท Reference ชนิดหนึ่ง แต่มันมีความพิเศษกว่า Reference ปกติ เพราะมันเป็นข้อมูลแบบ Two-word object หรือที่โปรแกรมเมอร์สาย Rust มักเรียกว่า Fat Pointer ซึ่งเก็บค่าสำคัญไว้แค่ 2 อย่างเท่านั้น:
ตำแหน่งเริ่มต้น (Pointer): ชี้ไปยังจุดแรกของข้อมูลที่เราสนใจใน Memory
ความยาวของข้อมูล (Length): บอกว่านับจากจุดเริ่มต้นไป เราจะเอาข้อมูลยาวเท่าไหร่
จุดเด่นที่ทำให้ Slice เหนือกว่าการตัดคำทั่วไป:
No Ownership: Slice เป็นแค่ผู้ยืมเสมอ มันไม่มีสิทธิ์เป็นเจ้าของข้อมูลจริง ดังนั้นเมื่อ Slice หมดอายุ ข้อมูลต้นทางก็ยังอยู่ปกติ
Zero-Copy: ไม่มีการคัดลอกข้อมูลใหม่ (No Allocation) มันแค่ชี้กลับไปที่ข้อมูลชุดเดิมที่มีอยู่แล้วบน Heap หรือ Stack ทำให้ประหยัดทรัพยากรแบบสุดๆ
Lightweight: ไม่ว่าข้อมูลต้นทางจะใหญ่ระดับกิกะไบต์ แต่ตัว Slice เองก็ยังมีขนาดเล็กนิดเดียว (แค่ Pointer + Length) เท่าเดิมเสมอ
2. String Slices (&str)
ในภาษา Rust ข้อมูลประเภท String Slice จะเขียนแทนด้วยตัวย่อ &str (อ่านว่า String Slice) ซึ่งวิธีสร้างก็ง่ายมากครับ เราจะใช้เครื่องหมาย [start..end] หรือที่เรียกว่า Range Syntax ในการเลือกช่วงข้อมูลที่ต้องการ
start: คือ Index เริ่มต้น (นับรวมตัวนี้ด้วย)
end: คือ Index ตัวสุดท้าย (แต่ไม่รวมตัวนี้! หรือที่เรียกว่า Exclusive)
Rust
fn main() {
let s = String::from("Superdev Academy");
// ยืมตั้งแต่ index 0 ถึง 7 (ตัวที่ 8 ไม่เอา)
let superdev = &s[0..8];
// ยืมตั้งแต่ index 9 ถึง 15 (ตัวที่ 16 ไม่เอา)
let academy = &s[9..16];
println!("First word: {}", superdev); // ผลลัพธ์: Superdev
println!("Second word: {}", academy); // ผลลัพธ์: Academy
}
🔥 Rust Trick: การเขียน Range แบบย่อ
Rust ออกแบบมาให้เราเขียนโค้ดได้กระชับขึ้น ถ้าเราต้องการเริ่มจากตัวแรกสุด หรือไปจนถึงตัวสุดท้าย เราไม่จำเป็นต้องใส่ตัวเลขครบก็ได้ครับ:
[..5]: เริ่มตั้งแต่ตัวแรกสุด (Index 0) ไปจนถึงก่อน Index 5[3..]: เริ่มจาก Index 3 ไปจนจบข้อความ (ไม่ต้องนับlenเอง)[..]: ยืมข้อมูลทั้งหมดตั้งแต่ตัวแรกถึงตัวสุดท้าย
3. Slice กับความปลอดภัย (Safety)
นี่คือจุดที่ Rust โชว์เหนือในเรื่องความปลอดภัยครับ เพราะการยืมข้อมูลบางส่วนอาจดูเหมือนง่าย แต่ถ้าจัดการไม่ดีในภาษาอื่น โปรแกรมอาจจะไปดึงข้อมูลมั่วซั่ว (Out of bounds) หรือข้อมูลที่ถูกลบไปแล้วมาแสดงผลได้ แต่ Rust ป้องกันเรื่องนี้ให้เรา 2 ชั้นครับ:
ชั้นที่ 1: ป้องกันการเข้าถึง Index ที่ไม่มีอยู่จริง (Bound Checking)
ถ้าคุณระบุ Index ของ Slice เกินขอบเขตของข้อมูลจริง (เช่น ตัวแปรมี 10 ตัวแต่จะเอาถึง Index ที่ 20) โปรแกรม Rust จะสั่ง Panic (หยุดการทำงาน) ทันทีในขั้นตอน Runtime เพื่อป้องกันไม่ให้โปรแกรมไปแอบอ่าน Memory ส่วนอื่นที่ตัวเองไม่มีสิทธิ์เข้าถึง
ชั้นที่ 2: กฎของ Borrowing ยังตามมาคุ้มครองถึงที่!
จำกฎเหล็กใน EP.8 ได้ไหมครับ? "ถ้ามีคนยืมอ่าน ห้ามคนอื่นมาแก้" กฎนี้ก็มีผลกับ Slice เช่นกันครับ ลองดูตัวอย่างนี้:
Rust
fn main() {
let mut s = String::from("hello world");
// ยืมอ่านข้อมูลแค่ช่วงแรก "hello" ผ่าน Slice
let word = &s[0..5];
// ❌ ERROR! คอมไพเลอร์จะด่าทันทีถ้าเราสั่ง s.clear()
// เพราะ s.clear() ต้องใช้สิทธิ์ในการแก้ไข (Mutable)
// แต่ตอนนี้ word ยัง "ถือสิทธิ์การยืมอ่าน" ค้างไว้อยู่!
// s.clear();
println!("The slice is: {}", word);
}
ทำไม Rust ถึงห้าม? เพราะถ้าเราสั่ง s.clear() ข้อมูลใน Memory จะถูกล้างทิ้งทันที แต่ตัวแปร word (ซึ่งเป็น Slice) ยังคงชี้ไปที่ตำแหน่งเดิมใน Memory ถ้า Rust ยอมให้รันต่อ word ก็จะกลายเป็น Dangling Reference (การชี้ไปที่ความว่างเปล่า) ซึ่งอันตรายมากครับ!
4. Array Slices
ไม่ใช่แค่ String เท่านั้นนะครับที่ทำแบบนี้ได้ Array ทั่วไปก็สามารถทำ Slice ได้เหมือนกัน! ซึ่งมีประโยชน์มหาศาลเวลาที่เรามีข้อมูลชุดใหญ่ แต่ต้องการส่งแค่เซกเมนต์ (Segment) บางส่วนเข้าไปประมวลผลในฟังก์ชัน โดยไม่ต้องเสียเวลา Copy ค่าออกมาเป็น Array ใหม่
Rust
fn main() {
let a = [10, 20, 30, 40, 50];
// ยืมข้อมูลจาก index 1 ถึง 2 (ไม่รวม index 3)
let slice = &a[1..3];
// ตรวจสอบค่า: slice จะมีค่าเป็น [20, 30]
assert_eq!(slice, &[20, 30]);
println!("Slice of array: {:?}", slice);
}
💡 เกร็ดความรู้เพิ่มเติม (Pro Insights):
Universal Concept: ใน Rust ข้อมูลประเภท Slice ของ Array จะมีหน้าตาเป็น
&[T](เมื่อ T คือประเภทข้อมูล เช่นi32)Flexibility: การใช้ Array Slice ช่วยให้โค้ดของคุณยืดหยุ่นขึ้นมาก เพราะคุณสามารถเขียนฟังก์ชันที่รับข้อมูลขนาดเท่าไหร่ก็ได้ (จะรับ 2 ตัวจาก Array ที่มี 100 ตัว หรือรับทั้ง 100 ตัวเลยก็ได้) โดยใช้รูปแบบการเขียนเดิมเสมอครับ
5. ทำไมเราควรใช้ &str แทน &String ในพารามิเตอร์?
นี่คือ Best Practice สำคัญของชาว Rustacean เลยครับ! หากคุณกำลังเขียนฟังก์ชันที่ต้องการแค่อ่านหรือใช้งานข้อความเฉยๆ โดยไม่ได้ต้องการเป็นเจ้าของ (Ownership) ให้คุณรับพารามิเตอร์เป็น &str (String Slice) แทนที่จะเป็น &String เสมอครับ
เหตุผลคือความยืดหยุ่นที่เหนือกว่า:
ถ้าคุณรับเป็น
&String: ฟังก์ชันนั้นจะรับได้แค่ตัวแปรประเภทStringเท่านั้นถ้าคุณรับเป็น
&str: ฟังก์ชันของคุณจะกลายเป็น "เครื่องจักรเอนกประสงค์" เพราะมันจะรับได้ทั้ง:String ปกติ (ผ่านเทคนิคที่เรียกว่า Deref Coercion ซึ่ง Rust จะแปลง
&Stringเป็น&strให้โดยอัตโนมัติ)String Slice (ข้อมูลบางส่วนที่เราตัดมา)
String Literal (ข้อความในอัญประกาศ
"..."ที่เราพิมพ์ลงไปตรงๆ)
สรุปสั้นๆ: การใช้
&strช่วยให้ฟังก์ชันของคุณใช้งานได้หลากหลายสถานการณ์มากกว่า โดยที่ประสิทธิภาพยังเร็วแรงเท่าเดิมครับ!
สรุป
Slice คือเครื่องมือทรงพลังที่ช่วยให้เราเข้าถึงข้อมูลบางส่วนได้อย่างรวดเร็วและประหยัดทรัพยากรที่สุด เพราะในเชิงเทคนิค มันคือการสร้าง "หน้าต่าง" เพื่อชี้ไปยังข้อมูลเดิมที่มีอยู่แล้ว แทนที่จะต้องเสียเวลาสร้างข้อมูลใหม่ให้หนักเครื่องนั่นเองครับ
📌 ใน EP. ถัดไป (EP.10): เราจะพักเรื่อง Memory กันสักนิด แล้วไปลุยเรื่องการจัดระเบียบข้อมูลให้เป็นระบบด้วย Structs ซึ่งเป็นพื้นฐานสำคัญของการเขียนโปรแกรมสไตล์ Object-Oriented ในแบบฉบับของ Rust... บอกเลยว่าห้ามพลาดครับ! แล้วเจอกัน 🦀✨
🎯 ติดตามความรู้สาย Dev แบบสุดจัดได้ที่: ไม่อยากพลาดบทความเทคนิคเชิงลึกและอัปเดตใหม่ๆ จากทีมงาน Superdev Academy ติดตามเราได้ทุกช่องทางที่นี่ครับ:
🔵 Facebook: Superdev Academy Thailand (อัปเดตข่าวสารและบทความใหม่)
🎬 YouTube: Superdev Academy Channel (ติวเข้มแบบวิดีโอ)
📸 Instagram: @superdevacademy (เกร็ดความรู้สั้นๆ และเบื้องหลังการทำงาน)
🎬 TikTok: @superdevacademy (Tips & Tricks ฉบับย่อยง่าย)
🌐 Website: superdevacademy.com (คลังบทความและคอร์สเรียนฉบับเต็ม)