การทำงานร่วมกับ Rust แบบไม่ปลอดภัย
ทำความเข้าใจเวลาและวิธีใช้บล็อก `unsafe` เพื่อข้ามการตรวจสอบความปลอดภัยของ Rust ทำให้ใช้ FFI และดำเนินการกับหน่วยความจำระดับต่ำได้
การทำงานร่วมกับ Rust แบบไม่ปลอดภัย เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 3 บทเรียน
Rust แบบไม่ปลอดภัย: บทนำ
ยินดีต้อนรับสู่Rust แบบไม่ปลอดภัย! แม้ Rust จะมีชื่อเสียงด้านการรับประกันความปลอดภัยของหน่วยความจำ แต่ก็มีบางสถานการณ์ที่คุณอาจจำเป็นต้องข้ามการตรวจสอบบางอย่าง
คีย์เวิร์ด unsafe ใน Rust ช่วยให้คุณทำเช่นนั้นได้ คีย์เวิร์ดนี้ไม่ได้มีไว้สำหรับเขียนโค้ดที่ "แย่" แต่เป็นเครื่องมือสำหรับกรณีการใช้งานขั้นสูงที่ต้องควบคุมหน่วยความจำหรือฮาร์ดแวร์โดยตรงมากขึ้น
พลังพิเศษห้าประการของโค้ดแบบไม่ปลอดภัย
เมื่อใช้บล็อก unsafe คุณจะเข้าถึงการดำเนินการพิเศษห้าประการที่โดยปกติคอมไพเลอร์ Rust จะป้องกันไว้:
- ยกเลิกการอ้างอิงตัวชี้ดิบ: เข้าถึงที่อยู่หน่วยความจำโดยตรง
- เรียกใช้ฟังก์ชันหรือเมธอด
unsafe: เรียกใช้ฟังก์ชันที่มีเงื่อนไขก่อนการทำงานซึ่งคอมไพเลอร์ตรวจสอบไม่ได้ - นำ trait
unsafeไปใช้: ประกาศว่าชนิดของคุณรักษาเงื่อนไขคงที่เฉพาะไว้ - เข้าถึงหรือแก้ไขตัวแปรสแตติกแบบเปลี่ยนแปลงได้: แชร์สถานะที่เปลี่ยนแปลงได้ทั่วทั้งโปรแกรม ซึ่งเสี่ยงต่อการแข่งกันเข้าถึงข้อมูล
- เข้าถึงฟิลด์ของ
union: อ่านค่าจาก union ซึ่งอาจไม่ใช่ชนิดที่ถูกต้องสำหรับข้อมูลปัจจุบัน
การยกเลิกการอ้างอิงตัวชี้ดิบ
ตัวชี้ดิบ คือที่อยู่หน่วยความจำที่ไม่มีการรับประกันความปลอดภัยตามปกติของ Rust คุณสามารถสร้างตัวชี้เหล่านี้จากการอ้างอิง (&T, &mut T) ได้ แต่การยกเลิกการอ้างอิงต้องทำภายในบล็อก unsafe
นั่นหมายความว่า คุณในฐานะผู้เขียนโปรแกรมต้องรับผิดชอบในการตรวจสอบว่าตัวชี้ถูกต้องและชี้ไปยังหน่วยความจำที่จัดสรรไว้
fn main() {
let mut num = 5;
let r1 = &num as *const i32; // Immutable raw pointer
let r2 = &mut num as *mut i32; // Mutable raw pointer
unsafe { // The `unsafe` block starts here
println!("r1 points to: {}", *r1);
*r2 = 10; // Modify data through mutable raw pointer
println!("r2 points to: {}", *r2);
} // The `unsafe` block ends here
println!("Num is now: {}", num);
}การเรียกใช้ฟังก์ชันแบบไม่ปลอดภัย
ฟังก์ชันบางรายการมีเครื่องหมายกำกับเป็น unsafe fn ซึ่งหมายความว่าฟังก์ชันนั้นมีเงื่อนไขก่อนการทำงานที่คอมไพเลอร์ Rust รับประกันไม่ได้ ตัวอย่างเช่น ฟังก์ชันอาจต้องการที่อยู่หน่วยความจำที่ถูกต้อง แต่ไม่สามารถตรวจสอบได้
การเรียกใช้ฟังก์ชันเหล่านี้ต้องครอบด้วยบล็อก unsafe เพื่อระบุว่าผู้เรียกเป็นผู้รับรองว่าเงื่อนไขก่อนการทำงานทั้งหมดเป็นจริง
unsafe fn dangerous_operation() {
println!("This operation could be dangerous if preconditions aren't met!");
}
fn main() {
println!("Attempting a dangerous operation...");
unsafe { // Calling an unsafe function requires `unsafe`
dangerous_operation();
}
println!("Operation completed.");
}ตัวแปรสแตติกแบบเปลี่ยนแปลงได้
โดยค่าเริ่มต้น Rust จะป้องกันสถานะส่วนกลางที่เปลี่ยนแปลงได้ เพื่อหลีกเลี่ยงการแข่งกันเข้าถึงข้อมูล อย่างไรก็ตาม คุณสามารถประกาศตัวแปรสแตติกแบบเปลี่ยนแปลงได้โดยใช้ static mut
การเข้าถึงหรือแก้ไขตัวแปรเหล่านี้ถือว่า unsafe เพราะหลายเธรดอาจพยายามเข้าถึงพร้อมกัน ซึ่งนำไปสู่พฤติกรรมที่ไม่กำหนดไว้ได้ การทำให้การเข้าถึงประสานกันอย่างถูกต้องเป็นความรับผิดชอบของคุณ
static mut COUNTER: i32 = 0; // A mutable static variable
fn add_to_counter(inc: i32) {
unsafe { // Modifying `static mut` requires `unsafe`
COUNTER += inc;
}
}
fn main() {
add_to_counter(5);
unsafe { // Reading `static mut` also requires `unsafe`
println!("COUNTER after first add: {}", COUNTER);
}
add_to_counter(10);
unsafe {
println!("COUNTER after second add: {}", COUNTER);
}
}การนำ trait แบบไม่ปลอดภัยไปใช้
trait บางรายการใน Rust มีเครื่องหมายกำกับเป็น unsafe trait ซึ่งหมายความว่าการนำ trait เหล่านี้ไปใช้ต้องรักษาเงื่อนไขคงที่บางอย่างที่คอมไพเลอร์ตรวจสอบไม่ได้
ตัวอย่างทั่วไปคือ trait Send และ Sync ซึ่งเกี่ยวข้องกับความปลอดภัยของเธรด หากคุณนำ unsafe trait ไปใช้ด้วยตนเอง คุณต้องใช้ unsafe impl Trait for Type และรับประกันคุณสมบัติด้านความปลอดภัยของมัน
สำหรับผู้เริ่มต้นส่วนใหญ่ คุณจะพบกรณีนี้ไม่บ่อยนัก เพราะ Rust มักจัดการให้โดยอัตโนมัติหรือผ่านสิ่งห่อหุ้มที่ปลอดภัย
การเข้าถึงฟิลด์ของ Union
union คือชนิดพิเศษที่เก็บค่าของหนึ่งในตัวแปรรูปแบบได้ในแต่ละขณะ แต่ตัวแปรรูปแบบทั้งหมดใช้ตำแหน่งหน่วยความจำเดียวกัน แนวคิดนี้คล้าย union ในภาษา C
การเข้าถึงฟิลด์ของ union ต้องทำภายในบล็อก unsafe เพราะคอมไพเลอร์ไม่ทราบว่าฟิลด์ใดกำลังใช้งานอยู่ การอ่านฟิลด์ที่ไม่ได้ใช้งานอาจทำให้เกิดพฤติกรรมที่ไม่กำหนดไว้หรือตีความข้อมูลผิดได้
union Data {
integer: u32,
float: f32,
}
fn main() {
let mut d = Data { integer: 42 }; // Initialize with an integer
unsafe {
// Accessing 'integer' is safe here
println!("Integer value: {}", d.integer);
// Accessing 'float' is unsafe, as 'integer' was initialized.
// This would interpret the integer's bits as a float.
// println!("Float value (unsafe): {}", d.float);
}
d.float = 3.14; // Now initialize with a float
unsafe {
// Accessing 'float' is safe now
println!("Float value: {}", d.float);
}
}สถานการณ์การใช้โค้ดแบบไม่ปลอดภัยในทางปฏิบัติ
แม้ควรใช้ unsafe เท่าที่จำเป็น แต่ก็มีความสำคัญต่อการเขียนโปรแกรมขั้นสูงหลายประเภท:
- อินเทอร์เฟซฟังก์ชันภายนอก (FFI): ติดต่อกับโค้ดที่เขียนด้วยภาษาอื่น เช่น ไลบรารี C หรือ C++
- การปรับปรุงประสิทธิภาพ: ในบางกรณี การข้ามการตรวจสอบของ Rust อาจเพิ่มประสิทธิภาพได้เล็กน้อยในส่วนสำคัญ แต่ควรวัดผลก่อน
- การเขียนโปรแกรมระบบระดับล่าง: เขียนระบบปฏิบัติการ ไดรเวอร์อุปกรณ์ หรือระบบฝังตัว
- การสร้างสิ่งห่อหุ้มที่ปลอดภัย: สร้างโครงสร้างข้อมูลหรือ API ที่ปลอดภัยบนพื้นฐานขององค์ประกอบแบบไม่ปลอดภัย เช่น วิธีสร้าง
Vec
ความรับผิดชอบของคุณเมื่อใช้โค้ดแบบไม่ปลอดภัย
เมื่อใช้ unsafe คุณต้องรับผิดชอบในการรักษาการรับประกันความปลอดภัยของ Rust ด้วยตนเอง ซึ่งหมายถึง:
- ตรวจสอบว่าหน่วยความจำถูกต้องและจัดแนวอย่างเหมาะสม
- ป้องกันการแข่งกันเข้าถึงข้อมูลเมื่อต้องจัดการกับสถานะที่แชร์และเปลี่ยนแปลงได้
- หลีกเลี่ยงตัวชี้ที่ลอยอยู่หรือข้อผิดพลาดจากการใช้หน่วยความจำหลังคืนคืน
- ตรวจสอบว่าเงื่อนไขก่อนการทำงานของฟังก์ชันทั้งหมดเป็นจริง
การใช้ unsafe ผิดวิธีอาจทำให้เกิดพฤติกรรมที่ไม่กำหนดไว้ ซึ่งเป็นข้อบกพร่องชนิดที่ร้ายแรงที่สุดและแก้ไขได้ยากมาก
ตรวจสอบความรู้เกี่ยวกับโค้ดแบบไม่ปลอดภัย
การดำเนินการใดต่อไปนี้จำเป็นต้องใช้บล็อก unsafe ใน Rust
ทบทวน: Rust แบบไม่ปลอดภัย
คุณได้เรียนรู้เกี่ยวกับRust แบบไม่ปลอดภัย ซึ่งเป็นความสามารถอันทรงพลังที่ช่วยให้คุณข้ามการตรวจสอบความปลอดภัยบางอย่างขณะคอมไพล์ของ Rust สำหรับสถานการณ์เฉพาะทางและขั้นสูง
โปรดจำไว้ว่า unsafe ไม่ได้ปิดตัวตรวจสอบการยืมทั้งหมด แต่จะโอนความรับผิดชอบด้านความปลอดภัยของหน่วยความจำและเงื่อนไขคงที่ทั้งหมดมาให้คุณในฐานะผู้เขียนโปรแกรม ใช้อย่างรอบคอบและระมัดระวังเป็นอย่างยิ่ง โดยทั่วไปใช้กับ FFI การปรับปรุงประสิทธิภาพระดับล่าง หรือการสร้างสิ่งห่อหุ้มที่ปลอดภัย
คำถามที่พบบ่อย
บทเรียน “การทำงานร่วมกับ Rust แบบไม่ปลอดภัย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การทำงานร่วมกับ Rust แบบไม่ปลอดภัย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 3 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การทำงานร่วมกับ Rust แบบไม่ปลอดภัย”
ทำความเข้าใจเวลาและวิธีใช้บล็อก `unsafe` เพื่อข้ามการตรวจสอบความปลอดภัยของ Rust ทำให้ใช้ FFI และดำเนินการกับหน่วยความจำระดับต่ำได้ คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน
บทเรียน “การทำงานร่วมกับ Rust แบบไม่ปลอดภัย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม
ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- มาโครแบบประกาศ (`macro_rules!`)
- มาโครเชิงกระบวนการ: Derive, Function
- การทำงานร่วมกับ Rust แบบไม่ปลอดภัย