Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Troubleshooting Index — ดัชนีแก้ปัญหา

รวมปัญหาและ Error ที่พบบ่อยในการเขียน Rust จัดเรียงตามหมวดหมู่เพื่อให้ค้นหาได้ง่าย พร้อมลิงก์ไปยังบทเรียนที่อธิบายรายละเอียดเพิ่มเติม


Ownership & Borrowing Errors

E0382: Use of moved value

อาการ: ใช้ตัวแปรหลังจากที่มันถูก Move ไปแล้ว

#![allow(unused)]
fn main() {
let s = String::from("hello");
let t = s;          // s ถูก Move ไปที่ t
println!("{}", s);  // ❌ E0382: value used here after move
}

สาเหตุ: ตัวแปรที่ไม่ได้ implement Copy trait จะถูกย้ายความเป็นเจ้าของ (Move) เมื่อ assign ให้ตัวแปรอื่นหรือส่งเข้าฟังก์ชัน

วิธีแก้:

  • ใช้ .clone() เพื่อสร้างสำเนา
  • ใช้ Reference (&s) แทนการส่งค่าตรงๆ
  • ปรับ API ให้รับ &self แทน self

📖 อ่านเพิ่มเติม: การเป็นเจ้าของของ self


E0502: Cannot borrow as mutable because it is also borrowed as immutable

อาการ: พยายาม Mutable Borrow ขณะที่ยังมี Immutable Borrow ค้างอยู่

#![allow(unused)]
fn main() {
let mut input = String::new();
let trimmed = input.trim();         // Immutable borrow
std::io::stdin().read_line(&mut input).unwrap();  // ❌ E0502
println!("{}", trimmed);
}

สาเหตุ: Rust ไม่อนุญาตให้มี &mut และ & ของตัวแปรเดียวกันอยู่พร้อมกัน เพื่อป้องกัน Data Race

วิธีแก้:

  • ใช้ .to_string() หรือ .to_owned() เพื่อสร้าง Owned Value แทนการเก็บ Reference
  • จัดลำดับ Scope ให้ Immutable Borrow จบก่อนที่จะเริ่ม Mutable Borrow

📖 อ่านเพิ่มเติม: กับดักของ read_line ในลูป — Borrow Checker Error


E0499: Cannot borrow as mutable more than once at a time

อาการ: พยายาม Mutable Borrow ตัวแปรเดียวกัน 2 ครั้งพร้อมกัน

#![allow(unused)]
fn main() {
let mut v = vec![1, 2, 3];
let first = &mut v[0];
let second = &mut v[1];  // ❌ E0499
}

สาเหตุ: กฎ Aliasing XOR Mutation — Mutable Reference ต้องมีได้เพียงตัวเดียวในขณะใดขณะหนึ่ง

วิธีแก้:

  • แยก Scope ของแต่ละ Mutable Borrow
  • ใช้ split_at_mut() สำหรับ Slice
  • พิจารณาใช้ Cell หรือ RefCell สำหรับ Interior Mutability

Lifetime Errors

Lifetime may not live long enough

อาการ: พยายาม Return Reference ที่มี Lifetime สั้นกว่าที่ Signature กำหนด

#![allow(unused)]
fn main() {
fn to_other_ctx(&mut self) -> OtherCtx<'s> {
    OtherCtx { window_state: self.window_state }
    // ❌ lifetime may not live long enough
}
}

สาเหตุ: การเข้าถึง Field ผ่าน &mut self เป็น Reborrow ที่มี Lifetime สั้นกว่า Lifetime ดั้งเดิมของ Field

วิธีแก้:

  • ใช้ Anonymous Lifetime '_ ใน Return Type: -> OtherCtx<'_>
  • หรือระบุ Lifetime แบบ Explicit ที่ผูกกับ &mut self

📖 อ่านเพิ่มเติม: Reborrowing และการแปลงโครงสร้างข้อมูล


E0106: Missing lifetime specifier

อาการ: ลืมระบุ Lifetime ใน Struct หรือ Function Signature ที่มี Reference

#![allow(unused)]
fn main() {
struct Foo {
    data: &str,  // ❌ E0106: missing lifetime specifier
}
}

วิธีแก้:

  • เพิ่ม Lifetime Parameter: struct Foo<'a> { data: &'a str }
  • หากเป็นกรณีง่ายใน Function ให้อาศัย Lifetime Elision Rules

Common Runtime Issues

Silent Bug: Buffer ไม่ถูก Clear ในลูป

อาการ: ข้อมูลเก่าสะสมใน String buffer ทำให้เงื่อนไขในลูปไม่ทำงานตามที่คาดหวัง โปรแกรมไม่พังแต่ทำงานผิด

#![allow(unused)]
fn main() {
let mut input = String::new();
loop {
    // ❌ ลืม input.clear()
    io::stdin().read_line(&mut input).unwrap();
    if input.trim() == "exit" { break; } // ไม่มีวันเป็น true หลังรอบแรก
}
}

สาเหตุ: read_line() ออกแบบมาให้ Append ข้อมูลต่อท้ายเสมอ ไม่ใช่ Overwrite

วิธีแก้:

  • เรียก .clear() ก่อน read_line() ทุกรอบ
  • หรือประกาศ String::new() ภายในลูป
  • หรือใช้ stdin().lock().lines() แทน

📖 อ่านเพิ่มเติม: กับดักของ read_line ในลูป — บั๊กเงียบ


Silent Bug: mut self กับ Copy Types

อาการ: เรียกเมธอดที่รับ mut self บน Copy Type แล้วค่าไม่เปลี่ยน

#![allow(unused)]
fn main() {
#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }

impl Point {
    fn move_wrong(mut self, dx: i32) {
        self.x += dx;  // แก้ไขแค่สำเนา!
    }
}
}

สาเหตุ: สำหรับ Copy Type การรับ self (by value) จะทำสำเนาเข้ามา การแก้ไขจึงเกิดขึ้นกับสำเนาเท่านั้น

วิธีแก้:

  • ใช้ &mut self หากต้องการแก้ไขค่าเดิม
  • หรือ Return Self กลับไป (Functional style): fn moved(self, dx: i32) -> Self

📖 อ่านเพิ่มเติม: การเป็นเจ้าของของ self — หลุมพราง Silent Bug


Quick Lookup by Error Code

Error Codeชื่อ Errorหมวดหมู่ลิงก์
E0106Missing lifetime specifierLifetimeด้านบน
E0382Use of moved valueOwnershipด้านบน
E0499Cannot borrow &mut more than onceBorrowingด้านบน
E0502Cannot borrow &mut while & existsBorrowingด้านบน

แหล่งข้อมูลเพิ่มเติม