Rust เป็นภาษาที่มุ่งเน้นความปลอดภัยของหน่วยความจำ (memory safety) เป็นหลัก โดยใช้ระบบ ownership และ borrow checker เพื่อตรวจสอบความถูกต้องของโค้ดตั้งแต่ compile time
แต่มีบางสถานการณ์ที่คุณจำเป็นต้อง “ก้าวข้ามกฎความปลอดภัย” เพื่อทำงานระดับล่าง เช่น การเข้าถึง pointer โดยตรง การจัดการหน่วยความจำแบบ manual หรือ FFI (Foreign Function Interface)
Rust มีทางออกให้คุณผ่าน unsafe
ซึ่งช่วยให้คุณควบคุมหน่วยความจำได้ด้วยตนเอง แต่ก็ต้องใช้ด้วยความระมัดระวัง
อะไรคือ unsafe Rust?
unsafe Rust ไม่ใช่โหมดใหม่ของภาษา แต่เป็นพื้นที่ที่ compiler อนุญาตให้คุณทำสิ่งที่ปกติแล้วผิดกฎ เช่น:
- Dereference raw pointer
- เรียก unsafe function
- เข้าถึง mutable static
- Implement unsafe trait
- Access union field
let x: i32 = 42; let r: *const i32 = &x; unsafe { println!("Value: {}", *r); // Dereference raw pointer }
ภายนอก unsafe block ยังคงถูกตรวจสอบตามปกติ Compiler จะไม่รับผิดชอบถ้าเกิดปัญหาภายใน unsafe block
ทำไมต้องใช้ unsafe?
- ทำงานกับ pointer/raw memory โดยตรง
- Performance optimization แบบ low-level
- Call C หรือภาษาอื่นผ่าน FFI
- เขียน low-level abstraction เช่น allocator, concurrency primitive
Raw Pointer
Raw pointer ใน Rust คือ *const T
และ *mut T
let mut num = 5; let r1 = &num as *const i32; let r2 = &mut num as *mut i32; unsafe { println!("{}", *r1); *r2 = 10; }
ต่างจาก reference ทั่วไป compiler จะไม่ตรวจสอบ lifetime หรือ borrow rule ให้
การเขียน FFI ด้วย unsafe
extern "C" { fn abs(input: i32) -> i32; } fn main() { unsafe { println!("abs(-3) = {}", abs(-3)); } }
เราสามารถใช้ extern block เพื่อเรียก C function ได้โดย unsafe

การจัดการหน่วยความจำแบบ Manual
use std::alloc::{alloc, dealloc, Layout}; fn main() { let layout = Layout::new::<u32>(); unsafe { let ptr = alloc(layout) as *mut u32; *ptr = 99; println!("value = {}", *ptr); dealloc(ptr as *mut u8, layout); } }
การใช้ allocator โดยตรงต้องระบุ layout และ deallocate เอง
Implement Unsafe Trait
unsafe trait MyUnsafeTrait { fn dangerous(&self); } unsafe impl MyUnsafeTrait for i32 { fn dangerous(&self) { println!("Calling unsafe on {}", self); } }
Static Mutable Variable
static mut COUNTER: u32 = 0; unsafe fn increment() { COUNTER += 1; }
เนื่องจาก static mut ไม่ปลอดภัยต่อการ race condition จึงต้องใช้ใน unsafe block
หลักการใช้ unsafe อย่างปลอดภัย
- จำกัด unsafe block ให้แคบที่สุด
- ห่อ unsafe ไว้ใน abstraction ที่ปลอดภัย (safe wrapper)
- อ่านเอกสารจาก
unsafe-code-guidelines
- ใช้เครื่องมือช่วยวิเคราะห์ เช่น
miri
,valgrind
Safe Abstraction Example
fn get_first_element(arr: &[i32]) -> Option<i32> { unsafe { if arr.len() > 0 { Some(*arr.as_ptr()) } else { None } } }
เราห่อ unsafe ในฟังก์ชันปลอดภัยโดยควบคุมเงื่อนไขก่อน dereference
ข้อดีของ unsafe
- เข้าถึง hardware หรือ memory ได้โดยตรง
- ทำ optimization ลึก ๆ ได้
- สร้าง library ที่ reusable ได้ เช่น
Vec
,Mutex
ก็ใช้ unsafe
ข้อเสีย
- เกิด segmentation fault, memory leak, data race ได้
- ยากต่อการ debug และ test
- ขัดกับหลัก safety ที่ Rust พยายามรักษา
สรุป
Unsafe Rust ไม่ได้แปลว่าไม่ปลอดภัยเสมอไป — มันคือพื้นที่ที่คุณต้องรับผิดชอบความปลอดภัยด้วยตนเอง
มันมีพลังมหาศาลในการควบคุม low-level และ performance-critical แต่ก็ต้องใช้ด้วยความเข้าใจลึกซึ้ง
สุดท้าย หากคุณสามารถออกแบบ abstraction ที่ใช้ unsafe ภายใน แต่ปลอดภัยภายนอก — คุณได้ใช้ Rust อย่างแท้จริง