0Pricing
Learn Rust Coding · บทเรียน

การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`

นำการจัดการข้อผิดพลาดตามแนวทางของภาษาไปใช้ด้วย enum `Result` ตัวดำเนินการ `?` และชนิดข้อผิดพลาดแบบกำหนดเอง เพื่อสร้างแอปพลิเคชันที่ทนทาน

การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result` เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 3 บทเรียน

การจัดการข้อผิดพลาดใน Rust

ข้อผิดพลาดเป็นส่วนหนึ่งของการเขียนโปรแกรม ใน Rust เราแบ่งข้อผิดพลาดออกเป็นสองประเภทหลัก ได้แก่ ข้อผิดพลาดที่กู้คืนได้และกู้คืนไม่ได้

  • ข้อผิดพลาดที่กู้คืนไม่ได้มักบ่งชี้ว่ามีข้อบกพร่อง ทำให้โปรแกรมหยุดทำงานด้วย panic!
  • ข้อผิดพลาดที่กู้คืนได้หมายถึงมีบางอย่างผิดพลาด แต่ยังจัดการได้ เช่น ไม่พบไฟล์

Rust ช่วยให้คุณจัดการข้อผิดพลาดที่กู้คืนได้อย่างเหมาะสม

`panic!` เทียบกับ `Result`

เมื่อเกิดข้อผิดพลาดที่กู้คืนไม่ได้ Rust จะเรียกใช้แมโคร panic! ซึ่งจะคลายสแตกและออกจากโปรแกรมของคุณ โดยมักพิมพ์ข้อความแสดงข้อผิดพลาดออกมาด้วย

สำหรับข้อผิดพลาดที่กู้คืนได้ Rust จะใช้ enum Result enum นี้จะบอกว่าการดำเนินการสำเร็จ (Ok) หรือล้มเหลว (Err) เพื่อให้โปรแกรมของคุณตัดสินใจได้ว่าจะดำเนินการอย่างไรต่อ

Enum `Result`

โดยแนวคิดแล้ว enum Result ถูกกำหนดไว้ดังนี้:

enum Result<T, E> {
  Ok(T),
  Err(E),
}

  • T แทนชนิดของค่าที่ส่งคืนเมื่อสำเร็จ
  • E แทนชนิดของข้อผิดพลาดที่ส่งคืนเมื่อล้มเหลว

นี่เป็นวิธีที่มีประสิทธิภาพในการระบุอย่างชัดเจนว่าฟังก์ชันอาจล้มเหลว

การจับคู่กับ `Result`

วิธีจัดการกับ Result ที่ใช้กันมากที่สุดคือการใช้นิพจน์ match วิธีนี้ช่วยให้คุณเรียกใช้บล็อกโค้ดที่แตกต่างกันได้ โดยพิจารณาจากว่า Result เป็น Ok หรือ Err

ลองเรียกใช้ตัวอย่างนี้ ซึ่งพยายามแยกวิเคราะห์ตัวเลข:

fn parse_and_add(text: &str) -> Result<i32, std::num::ParseIntError> {
    text.parse::<i32>()
}

fn main() {
    let num_str = "123";
    let result = parse_and_add(num_str);

    match result {
        Ok(num) => println!("Parsed number: {}", num),
        Err(e) => println!("Error parsing: {}", e),
    }

    let bad_str = "abc";
    let bad_result = parse_and_add(bad_str);

    match bad_result {
        Ok(num) => println!("Parsed number: {}", num),
        Err(e) => println!("Error parsing: {}", e),
    }
}

การแกะค่าจาก Result (อย่างระมัดระวัง!)

บางครั้งคุณอาจมั่นใจว่าการดำเนินการจะไม่ล้มเหลว หรือต้องการให้โปรแกรมหยุดทำงานหากเกิดข้อผิดพลาด เมธอดอย่าง unwrap() และ expect() จะดึงค่า Ok ออกมา

  • unwrap(): ส่งคืนค่า Ok หรือทำให้เกิด panic หากค่าเป็น Err
  • expect("message"): ทำงานเหมือน unwrap() แต่ให้คุณระบุข้อความ panic เองได้

ควรใช้งานสิ่งเหล่านี้เท่าที่จำเป็น โดยเฉพาะในชุดทดสอบหรือเมื่อความล้มเหลวนั้นกู้คืนไม่ได้อย่างแท้จริง

แนะนำตัวดำเนินการ `?`

การเขียนคำสั่ง match สำหรับ Result ทุกค่าซ้ำไปมาได้ ตัวดำเนินการ ? จึงเป็นทางลัดที่กระชับสำหรับการส่งต่อข้อผิดพลาด

เมื่อวางไว้หลังนิพจน์ที่ส่งคืนค่า Result ตัวดำเนินการ ? จะทำสองสิ่ง:

  • หาก Result เป็น Err ก็จะส่งคืนค่า Err จากฟังก์ชันปัจจุบันทันที
  • หาก Result เป็น Ok ก็จะแกะค่า Ok แล้วดำเนินการต่อ

ตัวดำเนินการ `?` ในการใช้งานจริง

ตัวดำเนินการ ? ช่วยให้การเขียนฟังก์ชันที่อาจล้มเหลวกระชับและสะอาดขึ้น โปรดจำไว้ว่าฟังก์ชันที่ใช้ ? จะต้องส่งคืนค่า Result (หรือ Option) ด้วยตัวเอง

ลองสังเกตว่า ? ทำให้การจัดการข้อผิดพลาดในตัวอย่างการอ่านไฟล์นี้ง่ายขึ้นอย่างไร:

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?; // Propagates error if file not found
    let mut s = String::new();
    f.read_to_string(&mut s)?; // Propagates error if read fails
    Ok(s)
}

fn main() {
    // Create a dummy file for the example to work
    // In a real scenario, this file might not exist
    std::fs::write("hello.txt", "CoddyKit User").unwrap();

    match read_username_from_file() {
        Ok(username) => println!("Username: {}", username),
        Err(e) => println!("Error reading username: {}", e),
    }

    // Clean up the dummy file
    std::fs::remove_file("hello.txt").unwrap();
}

ชนิดข้อผิดพลาดแบบกำหนดเอง

บางครั้งชนิดข้อผิดพลาดที่มีมาให้ไม่เฉพาะเจาะจงเพียงพอ คุณสามารถกำหนดชนิดข้อผิดพลาดแบบกำหนดเองโดยใช้ enum เพื่อแทนรูปแบบความล้มเหลวต่าง ๆ ของแอปพลิเคชัน

วิธีนี้ทำให้ข้อความแสดงข้อผิดพลาดชัดเจนขึ้น และช่วยให้ผู้เรียกจัดการข้อผิดพลาดแต่ละประเภทแตกต่างกันได้

รูปแบบที่ใช้กันทั่วไปคือการสร้าง enum ที่แสดงรายการข้อผิดพลาดทั้งหมดที่ฟังก์ชันหรือมอดูลอาจสร้างขึ้น

ทำให้ `?` ทำงานร่วมกับข้อผิดพลาดแบบกำหนดเอง

เพื่อให้ตัวดำเนินการ ? แปลงข้อผิดพลาดระดับล่าง (เช่น io::Error) เป็นชนิดข้อผิดพลาดแบบกำหนดเองของคุณโดยอัตโนมัติ enum ข้อผิดพลาดแบบกำหนดเองจะต้องนำทรีต From ไปใช้กับข้อผิดพลาดระดับล่างนั้น

วิธีนี้บอก Rust ว่าจะแปลงชนิดข้อผิดพลาดหนึ่งเป็นอีกชนิดหนึ่งอย่างไร ทำให้การส่งต่อข้อผิดพลาดเป็นไปอย่างราบรื่น

use std::io;
use std::fs::File;
use std::io::Read;

#[derive(Debug)]
enum MyError {
    Io(io::Error),
    Parse(std::num::ParseIntError)
}

impl From<io::Error> for MyError {
    fn from(error: io::Error) -> Self {
        MyError::Io(error)
    }
}

impl From<std::num::ParseIntError> for MyError {
    fn from(error: std::num::ParseIntError) -> Self {
        MyError::Parse(error)
    }
}

fn read_config(path: &str) -> Result<i32, MyError> {
    let mut file = File::open(path)?; // io::Error converted to MyError::Io
    let mut contents = String::new();
    file.read_to_string(&mut contents)?; // io::Error converted to MyError::Io
    let value = contents.trim().parse::<i32>()?; // ParseIntError converted to MyError::Parse
    Ok(value)
}

fn main() {
    // Create a dummy file for the example
    std::fs::write("config.txt", "123").unwrap();

    match read_config("config.txt") {
        Ok(val) => println!("Config value: {}", val),
        Err(e) => println!("Failed to read config: {:?}", e),
    }

    std::fs::remove_file("config.txt").unwrap(); // Clean up

    // Example with a non-existent file
    match read_config("non_existent.txt") {
        Ok(val) => println!("Config value: {}", val),
        Err(e) => println!("Failed to read config: {:?}", e),
    }
}

ตรวจสอบความเข้าใจของคุณ

พิจารณาโค้ด Rust ต่อไปนี้ หากไม่มีไฟล์ data.txt ผลลัพธ์จะเป็นอย่างไร

สรุป: การจัดการข้อผิดพลาดอย่างแข็งแกร่ง

คุณเชี่ยวชาญการจัดการข้อผิดพลาดอย่างแข็งแกร่งใน Rust แล้ว!

  • Enum Result: แยกความแตกต่างระหว่าง Ok(T) เมื่อสำเร็จ และ Err(E) เมื่อล้มเหลว
  • match: วิธีพื้นฐานในการจัดการรูปแบบต่าง ๆ ของ Result
  • ตัวดำเนินการ ?: ทางลัดอันทรงพลังสำหรับส่งต่อค่า Err ขึ้นไปตามสแตกการเรียก
  • ข้อผิดพลาดแบบกำหนดเอง: กำหนดชนิดข้อผิดพลาดของคุณเองโดยใช้ enum เพื่อความชัดเจนและการจัดการที่เฉพาะเจาะจง
  • ทรีต From: ช่วยให้แปลงข้อผิดพลาดระดับล่างเป็นชนิดข้อผิดพลาดแบบกำหนดเองได้อย่างราบรื่นเมื่อใช้ ?

ถัดไป ลองสำรวจความสามารถขั้นสูงของระบบชนิดข้อมูล!

คำถามที่พบบ่อย

บทเรียน “การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`”

นำการจัดการข้อผิดพลาดตามแนวทางของภาษาไปใช้ด้วย enum `Result` ตัวดำเนินการ `?` และชนิดข้อผิดพลาดแบบกำหนดเอง เพื่อสร้างแอปพลิเคชันที่ทนทาน คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน

บทเรียน “การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. จัดระเบียบโค้ดด้วยโมดูล
  2. จัดการสิ่งที่ต้องพึ่งพาด้วย Crates
  3. การจัดการข้อผิดพลาดอย่างแข็งแกร่งด้วย `Result`
← กลับไปที่ Learn Rust Coding