ตัวดำเนินการ ?
การส่งต่อแบบ Manual นั้นยุ่งยาก
หัวข้อที่มีชื่อว่า “การส่งต่อแบบ Manual นั้นยุ่งยาก”โดยไม่มีตัวดำเนินการ ? การส่งต่อข้อผิดพลาดจากฟังก์ชันที่เรียกต้องใช้นิพจน์ match ทุกครั้ง:
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> { let n = match s.parse::<i32>() { Ok(v) => v, Err(e) => return Err(e), }; Ok(n * 2)}รูปแบบนี้ — แกะ Ok หรือคืน Err แบบ early — เกิดขึ้นบ่อยมากจน Rust มีตัวดำเนินการเฉพาะให้เลย
ตัวดำเนินการ ?
หัวข้อที่มีชื่อว่า “ตัวดำเนินการ ?”การวาง ? หลังนิพจน์ Result ทำสิ่งเดียวกันกับ match ด้านบน:
- ถ้าค่าเป็น
Ok(v)จะประเมินเป็นv - ถ้าค่าเป็น
Err(e)จะคืนErr(e)ทันทีจากฟังก์ชันที่ครอบอยู่
ฟังก์ชันต้องคืน Result (หรือ Option) เพื่อให้ ? ทำงาน — คอมไพเลอร์บังคับใช้สิ่งนี้
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> { let n: i32 = s.parse()?; // ? returns early on Err Ok(n * 2)}การเชื่อมโยง ?
หัวข้อที่มีชื่อว่า “การเชื่อมโยง ?”เพราะ ? คืนค่า Ok โดยตรง คุณสามารถเรียกฟังก์ชันที่ล้มเหลวได้หลายตัวตามลำดับโดยไม่ต้องซ้อนกัน:
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> { let n: i32 = s.parse()?; Ok(n * 2)}
fn chain(a: &str, b: &str) -> Result<i32, ParseIntError> { let x = parse_and_double(a)?; let y = parse_and_double(b)?; Ok(x + y)}? แต่ละตัวจะแกะค่าสำเร็จหรือ short-circuit ฟังก์ชันทั้งหมด ไม่มีการ match ซ้อนกัน ไม่มีการ return แบบ manual
main ที่คืน Result
หัวข้อที่มีชื่อว่า “main ที่คืน Result”main ยังสามารถคืน Result<(), Box<dyn std::error::Error>> ซึ่งให้คุณใช้ ? ภายใน main ได้:
fn main() -> Result<(), Box<dyn std::error::Error>> { let n: i32 = "42".parse()?; println!("parsed: {}", n); Ok(())}Box<dyn std::error::Error> คือ trait object ที่สามารถเก็บประเภทข้อผิดพลาดใดก็ได้ ทำให้มีประโยชน์ใน main ที่คุณไม่ต้องการแก้ไขประเภทข้อผิดพลาดเดียวที่เป็น concrete
การแปลงประเภทข้อผิดพลาดด้วย ?
หัวข้อที่มีชื่อว่า “การแปลงประเภทข้อผิดพลาดด้วย ?”เมื่อประเภทข้อผิดพลาดที่คืนโดยฟังก์ชันที่เรียกแตกต่างจากประเภทข้อผิดพลาดของฟังก์ชันที่ครอบอยู่ ? จะเรียก From::from โดยอัตโนมัติเพื่อแปลง นี่คือวิธีที่ฟังก์ชันที่คืน MyError สามารถใช้ ? บนการเรียกที่คืน ParseIntError ได้ ตราบใดที่ From<ParseIntError> for MyError ถูก implement ไว้
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> { let n: i32 = s.parse()?; // ? returns early on Err Ok(n * 2)}
fn chain(a: &str, b: &str) -> Result<i32, ParseIntError> { let x = parse_and_double(a)?; let y = parse_and_double(b)?; Ok(x + y)}
fn main() -> Result<(), Box<dyn std::error::Error>> { let doubled = parse_and_double("21")?; println!("doubled: {}", doubled);
let sum = chain("10", "5")?; println!("chain(10, 5): {}", sum);
// Demonstrate early return on error match parse_and_double("abc") { Ok(v) => println!("ok: {}", v), Err(e) => println!("early return caught: {}", e), }
println!("main returned Ok(())"); Ok(())}Compiling…