ماڈیول اسباق (2/2)
خرابی سے نمٹنے اور؟ آپریٹر
زنگ کا فلسفہ آپ کو غلطیوں کے امکان کو واضح طور پر پہچاننے اور پروگرام کے مرتب ہونے سے پہلے ان کو سنبھالنے کے لیے اپنے کوڈ کی تشکیل کرنے کی ترغیب دیتا ہے۔
زنگ میں ہونے والی خرابیوں کو دو اہم زمروں میں تقسیم کیا گیا ہے: ناقابل بازیافت خرابیاں (جو panic! میکرو کے ذریعے فوری طور پر ختم ہوجاتی ہیں) اور قابل بازیافت خرابیاں (Result<T, E> قسم کا استعمال کرتے ہوئے منظم)۔
نتیجہ <T, E> قسم اور پیٹرن کی مماثلت
زیادہ تر بازیافت کی جانے والی غلطیاں Result<T, E> قسم لوٹاتی ہیں، جس کی تعریف اس طرح کی گئی ہے:
enum Result<T, E> {
Ok(T),
Err(E),
}ہم نتیجہ کا معائنہ کرنے کے لیے پیٹرن ملاپ کا استعمال کر سکتے ہیں:
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}? آپریٹر کے ساتھ پروپیگیشن میں خرابی۔
کسی فنکشن کو لاگو کرتے وقت، غلطی کو براہ راست اس کے اندر ہینڈل کرنے کے بجائے، ہم اکثر غلطی کو کال کرنے والے کو واپس کرنا چاہتے ہیں تاکہ وہ فیصلہ کر سکیں کہ کیا کرنا ہے۔ اس عمل کو غلطی پھیلانا کہا جاتا ہے۔
رسٹ ? آپریٹر کو غلطیوں کو پھیلانے کے لیے ایک نحوی شارٹ کٹ کے طور پر فراہم کرتا ہے۔ اگر Result کی قدر Ok ہے، تو Ok کی اندرونی قدر اظہار کے ذریعہ لوٹائی جاتی ہے۔ اگر یہ Err ہے تو، Err خرابی پورے موجودہ فنکشن سے واپس آ جاتی ہے جیسے ہم نے return Err(...) استعمال کیا ہو۔
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("username.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}[!اہم]
?آپریٹر صرف ان فنکشنز میں استعمال کیا جا سکتا ہے جو اس قدر کے ساتھ مطابقت پذیر قسم لوٹاتا ہے جس پر اس کا اطلاق ہوتا ہے (عام طور پرResult،Option، یاFromResidualکو نافذ کرنے والی اقسام)۔
حسب ضرورت غلطیاں
ہم غلطی کی انسانی پڑھنے کے قابل نمائندگی فراہم کرنے کے لیے std::fmt::Display خاصیت (اور اختیاری طور پر std::error::Error) کو لاگو کرکے اپنی مرضی کی غلطی کی اقسام کی وضاحت کر سکتے ہیں:
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {}", self.details)
}
}
impl std::error::Error for MyError {}خود ہی آزمائیں۔
مشق 1: کے ساتھ فائل پڑھنا آپریٹر
read_username_from_file فنکشن کو مکمل کریں تاکہ یہ ? آپریٹر فائل کو کھولنے اور اس کے مواد کو صارف نام کی تار میں پڑھنے سے پیدا ہونے والی غلطیوں کو پھیلانے کے لیے۔
اشارہ دکھائیں۔
غلطیاں پھیلانے کے لیے `?`کریکٹر کے بعد`File::open(...)`اور after`username_file.read_to_string(...)` شامل کریں۔
3 کوششوں کے بعد حل دستیاب ہے۔
مشق 2: ایک نمبر کو پارس اور دوگنا کریں۔
parse_and_double کے نام سے ایک فنکشن لکھیں جو سٹرنگ حوالہ &str کو قبول کرتا ہے اور نتیجہ<i32، std::num::ParseIntError> لوٹاتا ہے۔ فنکشن کو val.parse::<i32>() کے ساتھ سٹرنگ کو پارس کرنا چاہیے۔ تجزیہ کی غلطیوں کا پرچار کرنے کے لیے، اور کامیابی پر Ok میں لپی ہوئی دگنی قیمت واپس کر دیں۔
اشارہ دکھائیں۔
'val.parse::<i32>()?` اسٹرنگ کو پارس کرنے اور غلطی کو پھیلانے کے لیے استعمال کریں، پھر 'Ok(num \* 2)' واپس کریں۔
3 کوششوں کے بعد حل دستیاب ہے۔
مشق 3: اپنی مرضی کے مطابق غلطی کی وضاحت کرنا
CustomError نامی ایک خالی ڈھانچہ کی وضاحت کریں۔ fmt طریقہ کار میں 'Si e verificato un errore personalizzato' لکھ کر اس کے لیے std::fmt::ڈسپلی ٹریٹ کو لاگو کریں۔
اشارہ دکھائیں۔
'struct CustomError' کا اعلان کریں؛ اور `fmt`طریقہ کے اندر`write!(f, "Si e verificato un errore personalizzato") لکھ کر ڈسپلے کو لاگو کریں۔
3 کوششوں کے بعد حل دستیاب ہے۔