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

panic! করা নাকি না করা (To panic! or Not to panic!)

তাহলে আপনি কীভাবে সিদ্ধান্ত নেবেন কখন panic! কল করা উচিত এবং কখন Result রিটার্ন করা উচিত? যখন কোড প্যানিক করে, তখন পুনরুদ্ধার (recover) করার কোনো উপায় থাকে না। আপনি যেকোনো এরর পরিস্থিতিতে panic! কল করতে পারেন, چاہے পুনরুদ্ধারের কোনো সম্ভাব্য উপায় থাকুক বা না থাকুক, কিন্তু সেক্ষেত্রে আপনি কলিং কোডের পক্ষে সিদ্ধান্ত নিচ্ছেন যে পরিস্থিতিটি অপুনরুদ্ধারযোগ্য। যখন আপনি একটি Result ভ্যালু রিটার্ন করতে বেছে নেন, আপনি কলিং কোডকে বিকল্প (options) দেন। কলিং কোড তার পরিস্থিতির জন্য উপযুক্ত উপায়ে পুনরুদ্ধার করার চেষ্টা করতে পারে, অথবা এটি সিদ্ধান্ত নিতে পারে যে এই ক্ষেত্রে একটি Err ভ্যালু অপুনরুদ্ধারযোগ্য, তাই এটি panic! কল করতে পারে এবং আপনার পুনরুদ্ধারযোগ্য এররকে অপুনরুদ্ধারযোগ্য এররে পরিণত করতে পারে। অতএব, যখন আপনি এমন একটি ফাংশন ডিফাইন করছেন যা ব্যর্থ হতে পারে, তখন Result রিটার্ন করা একটি ভালো ডিফল্ট পছন্দ।

উদাহরণ, প্রোটোটাইপ কোড এবং টেস্টের মতো পরিস্থিতিতে, Result রিটার্ন করার পরিবর্তে প্যানিক করে এমন কোড লেখা বেশি উপযুক্ত। চলুন探讨 করি কেন, তারপর সেই পরিস্থিতিগুলো নিয়ে আলোচনা করি যেখানে কম্পাইলার বলতে পারে না যে ব্যর্থতা অসম্ভব, কিন্তু আপনি একজন মানুষ হিসেবে তা পারেন। অধ্যায়টি লাইব্রেরি কোডে প্যানিক করার সিদ্ধান্ত নেওয়ার বিষয়ে কিছু সাধারণ নির্দেশিকা দিয়ে শেষ হবে।

উদাহরণ, প্রোটোটাইপ কোড এবং টেস্ট (Examples, Prototype Code, and Tests)

যখন আপনি কোনো ধারণা ব্যাখ্যা করার জন্য একটি উদাহরণ লিখছেন, তখন শক্তিশালী এরর-হ্যান্ডলিং কোড অন্তর্ভুক্ত করলে উদাহরণটি কম স্পষ্ট হতে পারে। উদাহরণগুলিতে, এটা বোঝা যায় যে unwrap-এর মতো একটি মেথডের কল, যা প্যানিক করতে পারে, তা আপনার অ্যাপ্লিকেশন যেভাবে এরর হ্যান্ডেল করতে চায় তার জন্য একটি স্থানধারক (placeholder) হিসাবে বোঝানো হয়েছে, যা আপনার বাকি কোড কী করছে তার উপর ভিত্তি করে ভিন্ন হতে পারে।

একইভাবে, প্রোটোটাইপিংয়ের সময় unwrap এবং expect মেথডগুলি খুব সুবিধাজনক, যখন আপনি এরর কীভাবে হ্যান্ডেল করবেন তা সিদ্ধান্ত নিতে প্রস্তুত নন। আপনি যখন আপনার প্রোগ্রামকে আরও শক্তিশালী করতে প্রস্তুত হবেন, তখন এগুলি আপনার কোডে স্পষ্ট চিহ্ন রেখে যায়।

যদি একটি টেস্টে কোনো মেথড কল ব্যর্থ হয়, আপনি চাইবেন পুরো টেস্টটিই ব্যর্থ হোক, এমনকি যদি সেই মেথডটি পরীক্ষার অধীনে থাকা কার্যকারিতা না হয়। যেহেতু panic! হলো একটি টেস্টকে ব্যর্থ হিসাবে চিহ্নিত করার উপায়, তাই unwrap বা expect কল করাই ঠিক যা হওয়া উচিত।

এমন ক্ষেত্র যেখানে আপনার কাছে কম্পাইলারের চেয়ে বেশি তথ্য আছে

expect কল করাও উপযুক্ত হবে যখন আপনার কাছে অন্য কোনো যুক্তি থাকে যা নিশ্চিত করে যে Result-এর একটি Ok ভ্যালু থাকবে, কিন্তু সেই যুক্তিটি কম্পাইলার বুঝতে পারে না। আপনার কাছে এখনও একটি Result ভ্যালু থাকবে যা আপনাকে হ্যান্ডেল করতে হবে: আপনি যে অপারেশনটি কল করছেন তার সাধারণভাবে ব্যর্থ হওয়ার সম্ভাবনা এখনও আছে, যদিও আপনার নির্দিষ্ট পরিস্থিতিতে এটি যৌক্তিকভাবে অসম্ভব। যদি আপনি ম্যানুয়ালি কোড পরিদর্শন করে নিশ্চিত করতে পারেন যে আপনার কাছে কখনই একটি Err ভ্যারিয়েন্ট থাকবে না, তবে expect কল করা এবং আর্গুমেন্ট টেক্সটে আপনি কেন মনে করেন যে আপনার কখনই একটি Err ভ্যারিয়েন্ট থাকবে না তার কারণ নথিভুক্ত করা সম্পূর্ণ গ্রহণযোগ্য। এখানে একটি উদাহরণ:

fn main() {
    use std::net::IpAddr;

    let home: IpAddr = "127.0.0.1"
        .parse()
        .expect("Hardcoded IP address should be valid");
}

আমরা একটি হার্ডকোডেড স্ট্রিং পার্স করে একটি IpAddr ইনস্ট্যান্স তৈরি করছি। আমরা দেখতে পাচ্ছি যে 127.0.0.1 একটি বৈধ আইপি অ্যাড্রেস, তাই এখানে expect ব্যবহার করা গ্রহণযোগ্য। তবে, একটি হার্ডকোডেড, বৈধ স্ট্রিং থাকা parse মেথডের রিটার্ন টাইপ পরিবর্তন করে না: আমরা এখনও একটি Result ভ্যালু পাই, এবং কম্পাইলার এখনও আমাদের Result হ্যান্ডেল করতে বাধ্য করবে যেন Err ভ্যারিয়েন্ট একটি সম্ভাবনা, কারণ কম্পাইলার যথেষ্ট স্মার্ট নয় যে দেখতে পারে এই স্ট্রিংটি সর্বদা একটি বৈধ আইপি অ্যাড্রেস। যদি আইপি অ্যাড্রেস স্ট্রিংটি প্রোগ্রামে হার্ডকোড না হয়ে ব্যবহারকারীর কাছ থেকে আসত এবং তাই ব্যর্থতার সম্ভাবনা থাকত, আমরা অবশ্যই Result-কে আরও শক্তিশালী উপায়ে হ্যান্ডেল করতে চাইতাম। এই আইপি অ্যাড্রেসটি হার্ডকোডেড এই অনুমানটি উল্লেখ করা আমাদের ভবিষ্যতে যদি অন্য কোনো উৎস থেকে আইপি অ্যাড্রেস পাওয়ার প্রয়োজন হয় তবে expect-কে আরও ভালো এরর-হ্যান্ডলিং কোডে পরিবর্তন করতে উৎসাহিত করবে।

এরর হ্যান্ডলিংয়ের জন্য নির্দেশিকা (Guidelines for Error Handling)

আপনার কোড যখন একটি খারাপ অবস্থায় পড়তে পারে, তখন আপনার কোডকে প্যানিক করানো যুক্তিযুক্ত। এই প্রেক্ষাপটে, একটি খারাপ অবস্থা হলো যখন কোনো অনুমান, গ্যারান্টি, চুক্তি বা ইনভ্যারিয়েন্ট (invariant) ভেঙে যায়, যেমন যখন আপনার কোডে অবৈধ মান, পরস্পরবিরোধী মান বা অনুপস্থিত মান পাস করা হয়—এবং এর সাথে নিম্নলিখিত এক বা একাধিক বিষয় ঘটে:

  • খারাপ অবস্থাটি অপ্রত্যাশিত কিছু, এমন কিছুর বিপরীতে যা সম্ভবত মাঝে মাঝে ঘটবে, যেমন একজন ব্যবহারকারীর ভুল বিন্যাসে ডেটা প্রবেশ করানো।
  • এই বিন্দুর পরে আপনার কোডকে এই খারাপ অবস্থায় না থাকার উপর নির্ভর করতে হবে, প্রতিটি ধাপে সমস্যাটি পরীক্ষা করার পরিবর্তে।
  • আপনি যে টাইপগুলি ব্যবহার করেন সেগুলিতে এই তথ্য এনকোড করার কোনো ভালো উপায় নেই। আমরা অধ্যায় ১৮-এর “Encoding States and Behavior as Types”-এ এর একটি উদাহরণ দেখব।

যদি কেউ আপনার কোড কল করে এবং এমন মান পাস করে যা অর্থহীন, তবে যদি আপনি পারেন তবে একটি এরর রিটার্ন করাই ভালো যাতে লাইব্রেরির ব্যবহারকারী সিদ্ধান্ত নিতে পারে যে সেই ক্ষেত্রে তারা কী করতে চায়। তবে, যে ক্ষেত্রে চালিয়ে যাওয়া असुरक्षित বা ক্ষতিকারক হতে পারে, সেরা পছন্দ হতে পারে panic! কল করা এবং আপনার লাইব্রেরি ব্যবহারকারীকে তাদের কোডের বাগ সম্পর্কে সতর্ক করা যাতে তারা ডেভেলপমেন্টের সময় এটি ঠিক করতে পারে। একইভাবে, panic! প্রায়শই উপযুক্ত যদি আপনি আপনার নিয়ন্ত্রণের বাইরের এক্সটার্নাল কোড কল করছেন এবং এটি একটি অবৈধ অবস্থা রিটার্ন করে যা আপনার ঠিক করার কোনো উপায় নেই।

তবে, যখন ব্যর্থতা প্রত্যাশিত হয়, তখন panic! কল করার চেয়ে Result রিটার্ন করা বেশি উপযুক্ত। উদাহরণগুলির মধ্যে রয়েছে একটি পার্সারকে ভুল ফরম্যাটের ডেটা দেওয়া বা একটি HTTP অনুরোধ এমন একটি স্ট্যাটাস রিটার্ন করা যা নির্দেশ করে যে আপনি একটি রেট লিমিটে পৌঁছেছেন। এই ক্ষেত্রে, একটি Result রিটার্ন করা নির্দেশ করে যে ব্যর্থতা একটি প্রত্যাশিত সম্ভাবনা যা কলিং কোডকে সিদ্ধান্ত নিতে হবে কীভাবে হ্যান্ডেল করতে হবে।

যখন আপনার কোড এমন একটি অপারেশন সম্পাদন করে যা অবৈধ মান ব্যবহার করে কল করা হলে ব্যবহারকারীকে ঝুঁকির মধ্যে ফেলতে পারে, তখন আপনার কোডকে প্রথমে মানগুলি বৈধ কিনা তা যাচাই করা উচিত এবং মানগুলি বৈধ না হলে প্যানিক করা উচিত। এটি মূলত নিরাপত্তার কারণে: অবৈধ ডেটার উপর অপারেশন করার চেষ্টা আপনার কোডকে দুর্বলতার সম্মুখীন করতে পারে। এটিই প্রধান কারণ যে স্ট্যান্ডার্ড লাইব্রেরি panic! কল করবে যদি আপনি সীমার বাইরে মেমরি অ্যাক্সেসের চেষ্টা করেন: বর্তমান ডেটা স্ট্রাকচারের অন্তর্গত নয় এমন মেমরি অ্যাক্সেস করার চেষ্টা একটি সাধারণ নিরাপত্তা সমস্যা। ফাংশনগুলির প্রায়শই চুক্তি (contracts) থাকে: তাদের আচরণ শুধুমাত্র তখনই নিশ্চিত করা হয় যদি ইনপুটগুলি নির্দিষ্ট প্রয়োজনীয়তা পূরণ করে। চুক্তি লঙ্ঘন হলে প্যানিক করা অর্থপূর্ণ কারণ একটি চুক্তি লঙ্ঘন সর্বদা একটি কলার-সাইড বাগ নির্দেশ করে, এবং এটি এমন এক ধরনের এরর নয় যা আপনি চান কলিং কোডকে স্পষ্টভাবে হ্যান্ডেল করতে হোক। আসলে, কলিং কোডের পুনরুদ্ধার করার কোনো যুক্তিসঙ্গত উপায় নেই; কলিং প্রোগ্রামারদের কোড ঠিক করতে হবে। একটি ফাংশনের জন্য চুক্তি, বিশেষ করে যখন একটি লঙ্ঘন প্যানিক ঘটাবে, ফাংশনের জন্য API ডকুমেন্টেশনে ব্যাখ্যা করা উচিত।

তবে, আপনার সমস্ত ফাংশনে প্রচুর এরর চেক থাকা দীর্ঘ এবং বিরক্তিকর হবে। সৌভাগ্যবশত, আপনি Rust-এর টাইপ সিস্টেম (এবং এইভাবে কম্পাইলার দ্বারা করা টাইপ চেকিং) ব্যবহার করে আপনার জন্য অনেক চেক করতে পারেন। যদি আপনার ফাংশনের একটি নির্দিষ্ট টাইপ প্যারামিটার হিসাবে থাকে, আপনি আপনার কোডের যুক্তি নিয়ে এগিয়ে যেতে পারেন এটা জেনে যে কম্পাইলার ইতিমধ্যে নিশ্চিত করেছে যে আপনার কাছে একটি বৈধ মান আছে। উদাহরণস্বরূপ, যদি আপনার কাছে একটি Option-এর পরিবর্তে একটি টাইপ থাকে, আপনার প্রোগ্রাম কিছু না থাকার পরিবর্তে কিছু থাকার আশা করে। আপনার কোডকে তখন Some এবং None ভ্যারিয়েন্টের জন্য দুটি কেস হ্যান্ডেল করতে হবে না: এটি শুধুমাত্র নিশ্চিতভাবে একটি মান থাকার জন্য একটি কেস থাকবে। আপনার ফাংশনে কিছুই পাস করার চেষ্টা করা কোড এমনকি কম্পাইলও হবে না, তাই আপনার ফাংশনকে রানটাইমে সেই কেসটি পরীক্ষা করতে হবে না। আরেকটি উদাহরণ হলো একটি আনসাইন্ড ইন্টিজার টাইপ যেমন u32 ব্যবহার করা, যা নিশ্চিত করে যে প্যারামিটারটি কখনই নেতিবাচক নয়।

বৈধতা যাচাইয়ের জন্য কাস্টম টাইপ তৈরি করা (Creating Custom Types for Validation)

আসুন আমরা একটি বৈধ মান নিশ্চিত করার জন্য Rust-এর টাইপ সিস্টেম ব্যবহার করার ধারণাটিকে এক ধাপ এগিয়ে নিয়ে যাই এবং বৈধতা যাচাইয়ের জন্য একটি কাস্টম টাইপ তৈরি করার দিকে নজর দিই। অধ্যায় ২-এর অনুমান করার গেমটি মনে করুন যেখানে আমাদের কোড ব্যবহারকারীকে ১ থেকে ১০০-এর মধ্যে একটি সংখ্যা অনুমান করতে বলেছিল। আমরা আমাদের গোপন সংখ্যার সাথে এটি পরীক্ষা করার আগে ব্যবহারকারীর অনুমানটি সেই সংখ্যাগুলির মধ্যে ছিল কিনা তা কখনই যাচাই করিনি; আমরা কেবল যাচাই করেছি যে অনুমানটি পজিটিভ ছিল। এই ক্ষেত্রে, পরিণতি খুব গুরুতর ছিল না: আমাদের "Too high" বা "Too low" আউটপুট এখনও সঠিক হতো। কিন্তু ব্যবহারকারীকে বৈধ অনুমানের দিকে পরিচালিত করা এবং ব্যবহারকারী যখন সীমার বাইরের একটি সংখ্যা অনুমান করে তার জন্য ভিন্ন আচরণ করা একটি দরকারী উন্নতি হবে, যখন ব্যবহারকারী, উদাহরণস্বরূপ, অক্ষরের পরিবর্তে অক্ষর টাইপ করে।

এটি করার একটি উপায় হতে পারে অনুমানটিকে শুধুমাত্র একটি u32 এর পরিবর্তে একটি i32 হিসাবে পার্স করা যাতে সম্ভাব্য নেতিবাচক সংখ্যা அனுமதிக்க হয়, এবং তারপর সংখ্যাটি সীমার মধ্যে আছে কিনা তার জন্য একটি চেক যোগ করা, যেমন:

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        // --snip--

        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess: i32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        if guess < 1 || guess > 100 {
            println!("The secret number will be between 1 and 100.");
            continue;
        }

        match guess.cmp(&secret_number) {
            // --snip--
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}

if এক্সপ্রেশনটি পরীক্ষা করে যে আমাদের মান সীমার বাইরে কিনা, ব্যবহারকারীকে সমস্যা সম্পর্কে জানায়, এবং লুপের পরবর্তী পুনরাবৃত্তি শুরু করতে এবং আরেকটি অনুমানের জন্য জিজ্ঞাসা করতে continue কল করে। if এক্সপ্রেশনের পরে, আমরা guess এবং গোপন সংখ্যার মধ্যে তুলনা নিয়ে এগিয়ে যেতে পারি এটা জেনে যে guess ১ থেকে ১০০-এর মধ্যে রয়েছে।

তবে, এটি একটি আদর্শ সমাধান নয়: যদি এটি একেবারে গুরুত্বপূর্ণ হতো যে প্রোগ্রামটি শুধুমাত্র ১ থেকে ১০০-এর মধ্যে মান নিয়ে কাজ করবে, এবং এটির এই প্রয়োজনীয়তা সহ অনেক ফাংশন থাকত, তবে প্রতিটি ফাংশনে এইরকম একটি চেক থাকা ক্লান্তিকর হতো (এবং পারফরম্যান্সের উপর প্রভাব ফেলতে পারতো)।

পরিবর্তে, আমরা একটি ডেডিকেটেড মডিউলে একটি নতুন টাইপ তৈরি করতে পারি এবং বৈধতা যাচাইগুলি সর্বত্র পুনরাবৃত্তি করার পরিবর্তে টাইপের একটি ইনস্ট্যান্স তৈরি করার জন্য একটি ফাংশনে রাখতে পারি। এইভাবে, ফাংশনগুলির জন্য তাদের সিগনেচারে নতুন টাইপ ব্যবহার করা এবং তারা যে মানগুলি পায় তা আত্মবিশ্বাসের সাথে ব্যবহার করা নিরাপদ। লিস্টিং ৯-১৩ একটি Guess টাইপ সংজ্ঞায়িত করার একটি উপায় দেখায় যা শুধুমাত্র তখনই Guess-এর একটি ইনস্ট্যান্স তৈরি করবে যদি new ফাংশনটি ১ থেকে ১০০-এর মধ্যে একটি মান পায়।

#![allow(unused)]
fn main() {
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {value}.");
        }

        Guess { value }
    }

    pub fn value(&self) -> i32 {
        self.value
    }
}
}

উল্লেখ্য যে src/guessing_game.rs-এর এই কোডটি src/lib.rs-এ একটি মডিউল ডিক্লারেশন mod guessing_game; যোগ করার উপর নির্ভর করে যা আমরা এখানে দেখাইনি। এই নতুন মডিউলের ফাইলের মধ্যে, আমরা সেই মডিউলে Guess নামে একটি struct সংজ্ঞায়িত করি যার একটি value নামের ফিল্ড আছে যা একটি i32 ধারণ করে। এখানেই সংখ্যাটি সংরক্ষণ করা হবে।

তারপর আমরা Guess-এর উপর new নামে একটি অ্যাসোসিয়েটেড ফাংশন ইমপ্লিমেন্ট করি যা Guess মানের ইনস্ট্যান্স তৈরি করে। new ফাংশনটি value নামে একটি প্যারামিটার থাকার জন্য সংজ্ঞায়িত করা হয়েছে যার টাইপ i32 এবং একটি Guess রিটার্ন করার জন্য। new ফাংশনের বডির কোডটি value পরীক্ষা করে নিশ্চিত করে যে এটি ১ থেকে ১০০-এর মধ্যে আছে। যদি value এই পরীক্ষাটি পাস না করে, আমরা একটি panic! কল করি, যা কলিং কোড লিখছেন এমন প্রোগ্রামারকে সতর্ক করবে যে তাদের একটি বাগ আছে যা তাদের ঠিক করতে হবে, কারণ এই সীমার বাইরের একটি value দিয়ে একটি Guess তৈরি করা Guess::new যে চুক্তির উপর নির্ভর করছে তা লঙ্ঘন করবে। Guess::new যে শর্তে প্যানিক করতে পারে তা তার পাবলিক-ফেসিং API ডকুমেন্টেশনে আলোচনা করা উচিত; আমরা অধ্যায় ১৪-তে আপনার তৈরি করা API ডকুমেন্টেশনে একটি panic!-এর সম্ভাবনা নির্দেশকারী ডকুমেন্টেশন কনভেনশনগুলি কভার করব। যদি value পরীক্ষাটি পাস করে, আমরা একটি নতুন Guess তৈরি করি যার value ফিল্ড value প্যারামিটারে সেট করা হয় এবং Guess রিটার্ন করি।

এর পরে, আমরা value নামে একটি মেথড ইমপ্লিমেন্ট করি যা self ধার নেয়, অন্য কোনো প্যারামিটার নেই, এবং একটি i32 রিটার্ন করে। এই ধরনের মেথডকে কখনও কখনও getter বলা হয় কারণ এর উদ্দেশ্য হলো এর ফিল্ড থেকে কিছু ডেটা পাওয়া এবং তা রিটার্ন করা। এই পাবলিক মেথডটি প্রয়োজনীয় কারণ Guess struct-এর value ফিল্ডটি প্রাইভেট। এটা গুরুত্বপূর্ণ যে value ফিল্ডটি প্রাইভেট হোক যাতে Guess struct ব্যবহারকারী কোড সরাসরি value সেট করতে அனுமதிக்க না হয়: guessing_game মডিউলের বাইরের কোডকে একটি Guess-এর ইনস্ট্যান্স তৈরি করার জন্য অবশ্যই Guess::new ফাংশন ব্যবহার করতে হবে, যার ফলে নিশ্চিত করা হয় যে Guess::new ফাংশনের শর্ত দ্বারা পরীক্ষা করা হয়নি এমন কোনো value সহ একটি Guess থাকার কোনো উপায় নেই।

একটি ফাংশন যার একটি প্যারামিটার আছে বা শুধুমাত্র ১ থেকে ১০০-এর মধ্যে সংখ্যা রিটার্ন করে, সে তার সিগনেচারে ঘোষণা করতে পারে যে এটি একটি i32-এর পরিবর্তে একটি Guess নেয় বা রিটার্ন করে এবং তার বডিতে কোনো অতিরিক্ত চেক করার প্রয়োজন হবে না।

সারাংশ (Summary)

Rust-এর এরর-হ্যান্ডলিং ফিচারগুলি আপনাকে আরও শক্তিশালী কোড লিখতে সাহায্য করার জন্য ডিজাইন করা হয়েছে। panic! ম্যাক্রো সংকেত দেয় যে আপনার প্রোগ্রামটি এমন একটি অবস্থায় আছে যা এটি হ্যান্ডেল করতে পারে না এবং অবৈধ বা ভুল মান নিয়ে এগিয়ে যাওয়ার চেষ্টা করার পরিবর্তে আপনাকে প্রসেসটি বন্ধ করতে বলে। Result enum Rust-এর টাইপ সিস্টেম ব্যবহার করে নির্দেশ করে যে অপারেশনগুলি এমনভাবে ব্যর্থ হতে পারে যা থেকে আপনার কোড পুনরুদ্ধার করতে পারে। আপনি Result ব্যবহার করে আপনার কোড কলকারী কোডকে বলতে পারেন যে তাকেও সম্ভাব্য সফলতা বা ব্যর্থতা হ্যান্ডেল করতে হবে। উপযুক্ত পরিস্থিতিতে panic! এবং Result ব্যবহার করা আপনার কোডকে অনিবার্য সমস্যার মুখে আরও নির্ভরযোগ্য করে তুলবে।

এখন যেহেতু আপনি দেখেছেন যে স্ট্যান্ডার্ড লাইব্রেরি Option এবং Result enum-এর সাথে জেনেরিকগুলি কীভাবে দরকারী উপায়ে ব্যবহার করে, আমরা আলোচনা করব জেনেরিকগুলি কীভাবে কাজ করে এবং আপনি কীভাবে সেগুলি আপনার কোডে ব্যবহার করতে পারেন।