Skill

Enums এবং Pattern Matching (এনাম এবং প্যাটার্ন ম্যাচিং)

রাস্ট (Rust) - Computer Programming

211

Enums (এনাম)

রাস্টে এনাম (Enum) হল একটি ডেটা টাইপ যা বিভিন্ন ধরনের ভ্যারিয়েবল ভ্যালু ধারণ করতে সক্ষম। এটি এমন একটি টাইপ যা একাধিক সম্ভাব্য মানের মধ্যে কোনো একটি গ্রহণ করতে পারে। এনামগুলি মূলত মাল্টিপল চয়ন বা কাস্টম টাইপ তৈরি করতে ব্যবহৃত হয় এবং এটি কোডের পাঠযোগ্যতা এবং রক্ষণাবেক্ষণ সহজ করে তোলে।

এনামের মূল বৈশিষ্ট্য হলো, এটি একাধিক মান ধারণ করতে পারে, এবং আপনি সেই মানগুলোর উপর ভিত্তি করে বিভিন্ন আচরণ বা কার্যকরী কোড লিখতে পারেন। রাস্টে এনামগুলির একটি শক্তিশালী বৈশিষ্ট্য হচ্ছে, আপনি অ্যাট্রিবিউট ডাটা (associated data) যুক্ত করতে পারেন প্রতিটি ভ্যালুর সাথে, যা একে আরও শক্তিশালী করে তোলে।

এনাম ডিফাইন করা:

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn main() {
    let direction = Direction::Up;

    match direction {
        Direction::Up => println!("Going Up"),
        Direction::Down => println!("Going Down"),
        Direction::Left => println!("Going Left"),
        Direction::Right => println!("Going Right"),
    }
}

এখানে, Direction নামে একটি এনাম ডিফাইন করা হয়েছে, যা চারটি ভ্যালু ধারণ করতে পারে: Up, Down, Left, এবং Right। এরপর match স্টেটমেন্টের মাধ্যমে এই এনামটির মান পরীক্ষা করা হয়েছে।

এনামস উইথ ডেটা:

এনামগুলির মানের সাথে ডেটা যুক্ত করা সম্ভব। এর মাধ্যমে আপনি আরও জটিল ডেটা সংরক্ষণ করতে পারেন।

enum Shape {
    Circle(f64),      // Circle with radius
    Rectangle(f64, f64), // Rectangle with width and height
}

fn describe(shape: Shape) {
    match shape {
        Shape::Circle(radius) => println!("A circle with radius: {}", radius),
        Shape::Rectangle(width, height) => {
            println!("A rectangle with width: {} and height: {}", width, height)
        }
    }
}

fn main() {
    let circle = Shape::Circle(5.0);
    let rectangle = Shape::Rectangle(4.0, 6.0);

    describe(circle);
    describe(rectangle);
}

এখানে, Shape এনামে দুটি ভ্যালু রয়েছে, Circle এবং Rectangle, এবং প্রত্যেকটির সাথে সংশ্লিষ্ট ডেটা রয়েছে (যেমন, Circle এর জন্য একটি ফ্লোট, এবং Rectangle এর জন্য দুটি ফ্লোট)। match ব্যবহারের মাধ্যমে এই ডেটাগুলোর সাথে কাজ করা হয়েছে।


Pattern Matching (প্যাটার্ন ম্যাচিং)

রাস্টে প্যাটার্ন ম্যাচিং একটি অত্যন্ত শক্তিশালী বৈশিষ্ট্য, যা আপনাকে একাধিক প্যাটার্নের মধ্যে কোন একটি নির্বাচন করতে সাহায্য করে। এটি মূলত match কীবোর্ড দিয়ে করা হয় এবং এটি এনাম, অপশনাল টাইপস, লিস্টস, টুপলস এবং অন্যান্য ধরনের ডেটা স্ট্রাকচারগুলির সাথে কাজ করতে সাহায্য করে।

Match স্টেটমেন্ট:

match একটি কনডিশনাল স্টেটমেন্টের মতো কাজ করে, তবে এটি একাধিক প্যাটার্ন চেক করতে পারে। match এর মধ্যে কেস প্যাটার্ন ডিফাইন করা হয়, এবং এগুলোর মধ্যে যেকোনো একটি প্যাটার্ন মেলালে সেই ব্লকটি কার্যকরী হয়।

fn main() {
    let number = 7;

    match number {
        1 => println!("One!"),
        2 => println!("Two!"),
        3..=6 => println!("Between three and six!"), // range pattern
        _ => println!("Something else!"), // _ is the catch-all pattern
    }
}

এখানে, match স্টেটমেন্টটি number এর মানের উপর ভিত্তি করে বিভিন্ন আচরণ দেখাবে। যেমন, 1 এর জন্য "One!" প্রিন্ট হবে, 2 এর জন্য "Two!" প্রিন্ট হবে, এবং 3..=6 এর জন্য "Between three and six!" প্রিন্ট হবে। _ প্যাটার্নটি একটি catch-all হিসেবে কাজ করে, যা অন্য কোনো মানের জন্য ব্যবহৃত হয়।

Match with Enums:

এনামের সাথে প্যাটার্ন ম্যাচিং অত্যন্ত শক্তিশালী, কারণ আপনি এনামের প্রতিটি মানের জন্য আলাদা কোড ব্লক লিখতে পারেন। এটি এনাম ডেটার ভিত্তিতে আচরণ পরিবর্তন করতে সাহায্য করে।

enum TrafficLight {
    Red,
    Yellow,
    Green,
}

fn light_action(light: TrafficLight) {
    match light {
        TrafficLight::Red => println!("Stop!"),
        TrafficLight::Yellow => println!("Get ready!"),
        TrafficLight::Green => println!("Go!"),
    }
}

fn main() {
    let current_light = TrafficLight::Green;
    light_action(current_light);
}

এখানে, TrafficLight এনাম এবং match ব্যবহার করে বিভিন্ন ট্রাফিক লাইটের জন্য আলাদা আচরণ নির্ধারণ করা হয়েছে।


More Complex Pattern Matching

রাস্টে প্যাটার্ন ম্যাচিং আরও শক্তিশালী হতে পারে যদি আপনি tuple, struct, option types, বা nested enums এর সাথে কাজ করেন। যেমন, আপনি Some অথবা None এর মাধ্যমে একটি Option টাইপের সঙ্গে প্যাটার্ন ম্যাচিং করতে পারেন।

fn check_option(option: Option<i32>) {
    match option {
        Some(x) if x > 10 => println!("Greater than 10: {}", x),
        Some(x) => println!("Some value: {}", x),
        None => println!("No value"),
    }
}

fn main() {
    let some_value = Some(12);
    let none_value: Option<i32> = None;

    check_option(some_value);
    check_option(none_value);
}

এখানে, Some(x) if x > 10 প্যাটার্নটি একটি শর্ত যুক্ত করেছে, অর্থাৎ যদি Some ভ্যালু ১০ এর বেশি হয় তবে "Greater than 10" প্রিন্ট হবে।


সারাংশ

  • এনাম (Enum) একটি শক্তিশালী ডেটা টাইপ যা একাধিক ভ্যালু ধারণ করতে সক্ষম এবং ডেটার সঙ্গে আরও ডেটা অ্যাট্রিবিউট যুক্ত করতে পারে।
  • প্যাটার্ন ম্যাচিং (Pattern Matching) রাস্টের একটি অত্যন্ত শক্তিশালী বৈশিষ্ট্য যা ডেটা স্ট্রাকচার বা ভ্যালু নির্ধারণের জন্য ব্যবহৃত হয়, যেমন এনাম, অপশন, টুপল ইত্যাদির সাথে।
  • এটি কোডের পাঠযোগ্যতা এবং রক্ষণাবেক্ষণ সহজ করে এবং অত্যন্ত পরিষ্কারভাবে কন্ডিশনাল লজিক নির্মাণ করতে সাহায্য করে।
Content added By

Enums (Enumeration) কী?

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

রাস্টে, Enums ভেরিয়েবলগুলির জন্য আরও শক্তিশালী এবং লজিক্যাল ডেটা টাইপের ধারণা তৈরি করতে সাহায্য করে।

Enums এর মৌলিক সিনট্যাক্স

রাস্টে একটি এনাম তৈরি করতে enum কিওয়ার্ড ব্যবহার করা হয়। এর পরে আপনি এনামের নাম এবং তার মধ্যে সম্ভাব্য ভিন্ন ভিন্ন মান (variants) উল্লেখ করেন।

উদাহরণ:

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

এখানে, Direction একটি এনাম, যা চারটি ভিন্ন ভিন্ন মান ধারণ করে:

  • Up
  • Down
  • Left
  • Right

Enums এর ব্যবহার

এনাম ব্যবহারের অন্যতম সুবিধা হল, এটি কোডের পাঠযোগ্যতা এবং জটিলতা কমিয়ে আনে, কারণ আপনি সহজেই নির্দিষ্ট মান গুলোর সাথে কাজ করতে পারেন। এছাড়া, এনাম দিয়ে আপনি টাইপ সেফটি নিশ্চিত করতে পারেন, অর্থাৎ এনাম এমনভাবে তৈরি হয় যে ভুল টাইপের মান ব্যবহার করার সুযোগ থাকে না।

উদাহরণ:

fn move_player(direction: Direction) {
    match direction {
        Direction::Up => println!("Player moves up"),
        Direction::Down => println!("Player moves down"),
        Direction::Left => println!("Player moves left"),
        Direction::Right => println!("Player moves right"),
    }
}

fn main() {
    let direction = Direction::Up;
    move_player(direction);
}

ব্যাখ্যা:
এখানে, move_player ফাংশনটি Direction এনাম গ্রহণ করে এবং match স্টেটমেন্টের মাধ্যমে প্রত্যেকটি ভিন্ন মানের জন্য আলাদা কোড এক্সিকিউট করে। এনাম ব্যবহার করার মাধ্যমে আপনি সহজেই Up, Down, Left, বা Right এর মধ্যে নির্বাচন করতে পারেন, এবং কোডটি টাইপ সেফও থাকে।

বিভিন্ন ধরনের এনাম ভ্যালু (Enums with Data)

রাস্টে এনামের মানগুলি শুধুমাত্র কনস্ট্যান্ট (constant) হিসেবে সীমাবদ্ধ নয়। আপনি এনাম ভ্যারিয়েবলগুলোর সাথে ডেটা যুক্ত করতে পারেন। এটি এনামকে আরও শক্তিশালী এবং নমনীয় করে তোলে।

উদাহরণ:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn process_message(message: Message) {
    match message {
        Message::Quit => println!("Quit message"),
        Message::Move { x, y } => println!("Move to coordinates: ({}, {})", x, y),
        Message::Write(text) => println!("Writing message: {}", text),
        Message::ChangeColor(r, g, b) => println!("Changing color to RGB: ({}, {}, {})", r, g, b),
    }
}

fn main() {
    let msg = Message::Move { x: 10, y: 20 };
    process_message(msg);
}

ব্যাখ্যা:
এখানে, Message এনামটির চারটি ভিন্ন ভ্যালু রয়েছে:

  1. Quit (কোনো ডেটা নেই)
  2. Move { x, y } (স্ট্রাকচারাল ডেটা ধারণ করে)
  3. Write (একটি স্ট্রিং ধারণ করে)
  4. ChangeColor (তিনটি পূর্ণসংখ্যা ধারণ করে)

process_message ফাংশনে match ব্যবহার করে প্রত্যেকটি এনাম ভ্যালুর জন্য আলাদা কোড পরিচালনা করা হয়েছে। এনামের ভ্যালু Movex এবং y এর মান ধারণ করে, অন্যদিকে Write একটি স্ট্রিং গ্রহণ করে।

Enums এবং Option টাইপ

রাস্টে একটি বিশেষ ধরনের এনাম হল Option টাইপ, যা কোনো মানের উপস্থিতি বা অনুপস্থিতি নির্দেশ করে। এটি দুটি ভ্যালু ধারণ করে: Some(T) (যেখানে T কোনো টাইপ হতে পারে) এবং None (যেখানে কোন মান নেই)।

উদাহরণ:

fn find_item(index: usize) -> Option<&'static str> {
    let items = ["apple", "banana", "orange"];
    if index < items.len() {
        Some(items[index])
    } else {
        None
    }
}

fn main() {
    match find_item(1) {
        Some(item) => println!("Item found: {}", item),
        None => println!("Item not found"),
    }
}

ব্যাখ্যা:
এখানে, find_item ফাংশন একটি Option টাইপ রিটার্ন করে, যা Some(item) বা None হতে পারে। match স্টেটমেন্টের মাধ্যমে আমরা চেক করি যে ফলস্বরূপ কী পাওয়া গেছে।

সারাংশ

রাস্টের Enums একটি অত্যন্ত শক্তিশালী ডেটা টাইপ, যা প্রোগ্রামিংয়ের বিভিন্ন সমস্যা সমাধান করতে সাহায্য করে। এটি সিস্টেমের মধ্যে সীমিত মানের সেট তৈরি করতে সাহায্য করে এবং কোডের সুরক্ষা এবং পাঠযোগ্যতা বৃদ্ধি করে। এনাম এর মাধ্যমে আপনি বিভিন্ন ধরনের ডেটা গ্রুপ করতে পারেন এবং টাইপ সেফটি বজায় রেখে কোড লিখতে পারেন।

Content added By

Option Enum

Option হল রাস্টের একটি বিশেষ ধরনের enum, যা মূলত মান থাকতে পারে অথবা নাও থাকতে পারে এমন পরিস্থিতি মোকাবেলা করার জন্য ব্যবহৃত হয়। এটি মূলত সেই পরিস্থিতি নির্দেশ করে যেখানে কোনো মানের অস্তিত্ব না থাকার সম্ভাবনা থাকে, যেমন একটি অপশনাল মান যা সফল বা অ-সফল হতে পারে। এটি দুটি ভ্যারিয়েন্ট ধারণ করে: Some(T) এবং None

  • Some(T): একটি মান ধারণ করে।
  • None: মানের অভাব নির্দেশ করে।

Option Enum এর ব্যবহারের উদাহরণ:

fn find_index(arr: &[i32], target: i32) -> Option<usize> {
    for (index, &value) in arr.iter().enumerate() {
        if value == target {
            return Some(index); // Target found, return Some(index)
        }
    }
    None // Target not found, return None
}

fn main() {
    let arr = [1, 2, 3, 4, 5];
    let index = find_index(&arr, 3);

    match index {
        Some(i) => println!("Found at index: {}", i),
        None => println!("Not found!"),
    }
}

Output:

Found at index: 2

এখানে, find_index ফাংশনটি একটি সংখ্যা খোঁজার চেষ্টা করে। যদি সংখ্যা পাওয়া যায়, তাহলে Some(index) ফেরত দেয়। যদি না পাওয়া যায়, তবে None ফেরত দেয়। আমরা match এর মাধ্যমে এটি পরীক্ষা করি এবং ফলাফল অনুযায়ী আউটপুট প্রদান করি।

Option Enum এর প্রয়োগের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য:

  • নাল পয়েন্টার এক্সসেপ্টশন থেকে মুক্তি: Option ব্যবহার করে কোডে null পয়েন্টারের মতো সমস্যাগুলো সহজেই মোকাবেলা করা যায়। এটি নিশ্চিত করে যে আপনি কোনও মান পাবেন কিনা তা আগে থেকে চেক করতে পারবেন।
  • কোডের স্বচ্ছতা এবং নিরাপত্তা: Option ব্যবহারের মাধ্যমে কোডের কার্যক্রম আরও নিরাপদ এবং বাগ-মুক্ত হয়।

Result Enum

Result হল রাস্টের আরেকটি enum, যা সফল বা ব্যর্থ ফলাফলগুলিকে পরিচালনা করতে ব্যবহৃত হয়। এটি দুটি ভ্যারিয়েন্ট ধারণ করে: Ok(T) এবং Err(E)

  • Ok(T): সাফল্য নির্দেশ করে এবং এটি একটি মান ধারণ করে।
  • Err(E): ব্যর্থতা নির্দেশ করে এবং এটি একটি ত্রুটি ধারণ করে।

Result ব্যবহৃত হয় মূলত ত্রুটির সাথে সম্পর্কিত পরিস্থিতিতে, যেমন ফাইল পড়া বা নেটওয়ার্ক সংযোগ, যেখানে কিছু কিছু পরিস্থিতিতে ত্রুটি ঘটতে পারে এবং এটি প্রোগ্রামটির নিয়ন্ত্রণ ব্যবস্থা পরিচালনার জন্য উপযুক্ত।

Result Enum এর ব্যবহারের উদাহরণ:

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

fn read_file(file_name: &str) -> Result<String, io::Error> {
    let mut file = File::open(file_name)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents) // File read successfully
}

fn main() {
    match read_file("example.txt") {
        Ok(contents) => println!("File contents: \n{}", contents),
        Err(e) => println!("Error reading file: {}", e),
    }
}

Output (অথবা ত্রুটি):

Error reading file: No such file or directory (os error 2)

এখানে, read_file ফাংশনটি একটি ফাইল পড়ার চেষ্টা করছে। যদি ফাইলটি পাওয়া যায় এবং পড়া সম্ভব হয়, তাহলে Ok(contents) ফেরত দিবে। অন্যথায়, Err(e) ত্রুটি ফেরত দিবে, যা আমরা match ব্যবহার করে পরীক্ষা করছি।

Result Enum এর প্রয়োগের কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য:

  • ত্রুটি ব্যবস্থাপনা: রাস্টে Result ব্যবহারের মাধ্যমে আপনি ত্রুটির সম্ভাবনা সুনির্দিষ্টভাবে ধারণ করতে পারেন। এটি কোডকে আরও পাঠযোগ্য এবং পূর্বানুমানযোগ্য করে তোলে, কারণ ত্রুটির সম্ভাবনা থাকা ফাংশনগুলোতে Result ব্যবহৃত হয়।
  • Error Propagation: Result সহজেই ত্রুটির প্রোপাগেশন (propagation) করতে সাহায্য করে। যেমন, ? অপারেটর ব্যবহার করে ত্রুটি সহজেই উর্ধ্বতন ফাংশনে পাঠানো যেতে পারে।

Option এবং Result এর মধ্যে পার্থক্য:

  • Option: ব্যবহার করা হয় এমন পরিস্থিতিতে যেখানে কোনও মান থাকতে পারে অথবা নাও থাকতে পারে, যেমন একটি অপশনাল মান যা অস্তিত্বহীন হতে পারে।
  • Result: ব্যবহার করা হয় এমন পরিস্থিতিতে যেখানে একটি প্রক্রিয়া সফল হতে পারে অথবা ত্রুটিপূর্ণ হতে পারে, যেমন ফাইল পড়া বা নেটওয়ার্ক সংযোগ, যেখানে সফল বা ব্যর্থ হওয়া উভয়ই সম্ভাব্য।

Option Enum:

  • ব্যবহৃত হয় যেখানে মানের অভাব থাকতে পারে এবং আমরা যদি মান না পাই, তা None ফেরত দেয়।

Result Enum:

  • ব্যবহৃত হয় যেখানে ত্রুটি ঘটতে পারে এবং সেক্ষেত্রে ফলস্বরূপ ত্রুটি (Error) বা সাফল্য (Success) ফেরত দেয়।

সারাংশ:

  • Option এবং Result দুইটি অত্যন্ত গুরুত্বপূর্ণ enum ধরনের ডেটা টাইপ রাস্টে, যা ত্রুটি এবং অপশনাল মানগুলোর সাথে কাজ করার জন্য ব্যবহৃত হয়। Option দিয়ে মানের অস্তিত্ব চেক করা হয়, আর Result দিয়ে কার্যকরী ত্রুটি ব্যবস্থাপনা করা হয়।
  • এই দুটি enum রাস্টে কোডের নিরাপত্তা এবং শক্তিশালী ত্রুটি ব্যবস্থাপনা নিশ্চিত করতে সাহায্য করে, যা সি বা সি++ এর মতো ভাষায় সম্ভব নয়।
Content added By

Pattern Matching (প্যাটার্ন মেচিং)

রাস্টে Pattern Matching একটি শক্তিশালী বৈশিষ্ট্য, যা আপনাকে ডেটার সাথে মিল রেখে বিভিন্ন কন্ডিশন পরীক্ষা করতে এবং বিভিন্ন ধরনের প্যাটার্নকে চিহ্নিত করতে সাহায্য করে। এটি সাধারণত match এক্সপ্রেশন দিয়ে ব্যবহার করা হয়, যা C, C++, অথবা অন্যান্য ভাষার switch স্টেটমেন্টের মতো কাজ করে, তবে আরো শক্তিশালী এবং নমনীয়।

Pattern Matching ব্যবহারের মাধ্যমে আপনি কোনো ডেটা বা ভেরিয়েবলের ধরন, মান, অবস্থান ইত্যাদি চেক করতে পারেন এবং সেই অনুযায়ী কাজ করতে পারেন।


match এক্সপ্রেশন

match এক্সপ্রেশনটি রাস্টের pattern matching এর মূল উপাদান। এটি একটি এক্সপ্রেশন যা বিভিন্ন প্যাটার্নের সাথে ডেটা মিলিয়ে সঠিক কোড ব্লক নির্বাচন করে এক্সিকিউট করে।

Syntax:

match value {
    pattern1 => expression1,
    pattern2 => expression2,
    _ => default_expression, // Catch-all case, equivalent to 'else'
}
  • value: যে ভেরিয়েবল বা এক্সপ্রেশনটি আপনি মিলাতে চান।
  • pattern1, pattern2: প্যাটার্ন যা আপনি যাচাই করতে চান। প্যাটার্নগুলি ভ্যালু অনুযায়ী বিভিন্ন ধরণের হতে পারে, যেমন নাম্বার, টিউপল, স্ট্রাকচার ইত্যাদি।
  • _: এটি একটি ডিফল্ট প্যাটার্ন, যা কোনো অন্যান্য প্যাটার্ন মেলেনি এমন ক্ষেত্রে এক্সিকিউট হয়।

match এক্সপ্রেশনের উদাহরণ

১. নম্বর প্যাটার্ন

fn main() {
    let x = 5;

    match x {
        1 => println!("x is one"),
        2 => println!("x is two"),
        3 => println!("x is three"),
        _ => println!("x is something else"), // Catch-all
    }
}

এখানে, x এর মান ৫, যা কোনো নির্দিষ্ট প্যাটার্নের সাথে মেলে না, তাই _ প্যাটার্নটি কাজ করবে এবং আউটপুট হবে "x is something else"

২. কন্ডিশনাল প্যাটার্ন

fn main() {
    let x = 10;

    match x {
        n if n < 10 => println!("x is less than 10"),
        n if n == 10 => println!("x is equal to 10"),
        n if n > 10 => println!("x is greater than 10"),
        _ => println!("Something went wrong"), // Catch-all case
    }
}

এখানে, match এক্সপ্রেশনটি শর্ত (condition) অনুযায়ী n এর মান যাচাই করে। n if n == 10 শর্তটি সত্য হলে "x is equal to 10" প্রিন্ট হবে।

৩. টিউপল প্যাটার্ন

fn main() {
    let pair = (2, 3);

    match pair {
        (0, y) => println!("First is zero, second is {}", y),
        (x, 0) => println!("First is {}, second is zero", x),
        (x, y) => println!("First is {}, second is {}", x, y),
    }
}

এখানে, pair একটি টিউপল যা (2, 3)match এক্সপ্রেশনটি প্রথম দুটি প্যাটার্নের সাথে মেলে না, তবে তৃতীয় প্যাটার্নটি সঠিক মেলে এবং আউটপুট হবে "First is 2, second is 3"

৪. ইউনিয়ন টাইপ (Enums) প্যাটার্ন

রাস্টে enums ব্যবহারে match এক্সপ্রেশন বেশ শক্তিশালী হয়ে ওঠে। ইউনিয়ন টাইপের মানগুলি match এর মাধ্যমে সহজে চিহ্নিত এবং প্রক্রিয়া করা যায়।

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn main() {
    let move_direction = Direction::Up;

    match move_direction {
        Direction::Up => println!("Moving up"),
        Direction::Down => println!("Moving down"),
        Direction::Left => println!("Moving left"),
        Direction::Right => println!("Moving right"),
    }
}

এখানে, move_direction হল একটি enum এবং match এক্সপ্রেশনটি ডিরেকশন অনুযায়ী সঠিক কোড ব্লক এক্সিকিউট করবে। move_direction এর মান Direction::Up হলে আউটপুট হবে "Moving up"


match এর শক্তিশালী বৈশিষ্ট্যসমূহ

  • ডিফল্ট _ প্যাটার্ন: যদি কোনো নির্দিষ্ট প্যাটার্ন মেলে না, তবে _ দিয়ে ডিফল্ট আউটপুট দেওয়া যেতে পারে।
  • গহীন প্যাটার্ন: প্যাটার্নের মধ্যে আরও গহীন ভাবে মূল্যায়ন করা সম্ভব (যেমন টিউপল বা enum ব্যবহার করে আরও বেশি প্যাটার্ন মেচিং করা)।
  • ইন্টারনাল ভেরিয়েবল অ্যাক্সেস: আপনি প্যাটার্নের মধ্যে ডেটা (যেমন টিউপল বা struct) বের করে এবং সেটি ব্যবহার করতে পারেন।
  • নামকরণ: আপনি প্যাটার্নে কোনো পরিবর্তনশীল নাম ব্যবহার করতে পারেন যাতে ডেটার মানকে তার নিজস্ব ভেরিয়েবলে সংরক্ষণ করতে পারেন।

সারাংশ

রাস্টের match এক্সপ্রেশন একটি শক্তিশালী প্যাটার্ন মেচিং প্রযুক্তি যা বিভিন্ন ডেটা প্যাটার্নের সাথে সহজে মেলে এবং সঠিক কোড এক্সিকিউট করে। এটি প্রোগ্রামিংয়ের ক্ষেত্রে শর্ত নির্ধারণ এবং বিভিন্ন ডেটা টাইপের সাথে কাজ করতে অত্যন্ত কার্যকর এবং নমনীয় পদ্ধতি প্রদান করে। match স্টেটমেন্টটি সি এবং সি++ এর switch স্টেটমেন্টের তুলনায় অনেক বেশি কার্যকর এবং সুরক্ষিত।

Content added By

Enum এবং Struct: ভূমিকা

  • Enum (এনাম): enum একটি ডেটা টাইপ, যা বিভিন্ন ধরণের মান ধারণ করতে পারে। প্রতিটি মান একটি ভিন্ন ভিন্ন ভ্যারিয়েবল হতে পারে।
  • Struct (স্ট্রাকচার): struct একাধিক ভেরিয়েবলের একটি গ্রুপ যা একটি একক ইউনিট হিসেবে কাজ করে। এটি সাধারণত ডেটা ধারণ করতে ব্যবহৃত হয়।

রাস্টে enum এবং struct একসাথে ব্যবহার করা খুবই সাধারণ। এর মাধ্যমে আপনি আরও জটিল ডেটা কাঠামো তৈরি করতে পারেন, যেখানে enum ভিন্ন ধরণের অবজেক্টগুলিকে গ্রুপ করবে এবং struct তাদের সুনির্দিষ্ট প্রপার্টি বা ডেটা সংরক্ষণ করবে।


Enum এবং Struct এর কম্বিনেশন উদাহরণ

ধরা যাক, আমরা একটি Shape নামক enum তৈরি করতে চাই, যা বিভিন্ন ধরনের আকৃতির তথ্য ধারণ করবে যেমন Circle, Rectangle ইত্যাদি। প্রতিটি আকৃতির ভিন্ন ভিন্ন প্রপার্টি থাকতে পারে, যেমন বৃত্তের জন্য রেডিয়াস এবং আয়তক্ষেত্রের জন্য প্রস্থ এবং উচ্চতা।

// প্রথমে struct গুলি ডিফাইন করা হচ্ছে:
struct Circle {
    radius: f64,
}

struct Rectangle {
    width: f64,
    height: f64,
}

// Enum ডিফাইন করা হচ্ছে:
enum Shape {
    Circle(Circle),
    Rectangle(Rectangle),
}

fn main() {
    // একটি Circle তৈরি করা
    let c = Circle { radius: 5.0 };

    // একটি Rectangle তৈরি করা
    let r = Rectangle {
        width: 10.0,
        height: 20.0,
    };

    // Shape enum এ Circle এবং Rectangle পাস করা
    let shape1 = Shape::Circle(c);
    let shape2 = Shape::Rectangle(r);

    // Shape অনুযায়ী কাজ করা
    match shape1 {
        Shape::Circle(c) => println!("Circle with radius: {}", c.radius),
        Shape::Rectangle(r) => println!("Rectangle with width: {} and height: {}", r.width, r.height),
    }

    match shape2 {
        Shape::Circle(c) => println!("Circle with radius: {}", c.radius),
        Shape::Rectangle(r) => println!("Rectangle with width: {} and height: {}", r.width, r.height),
    }
}

ব্যাখ্যা:

  1. Structs:
    • Circle struct এ একটি ফিল্ড আছে যা radius নামে একটি f64 টাইপের ভেরিয়েবল ধারণ করে।
    • Rectangle struct এ দুটি ফিল্ড আছে যা width এবং height নামে দুটি f64 টাইপের ভেরিয়েবল ধারণ করে।
  2. Enum:
    • Shape নামক একটি enum ডিফাইন করা হয়েছে, যেখানে দুটি ভিন্ন ধরণের আর্কিটেকচার রয়েছে:
      • Circle(Circle): এটি Circle struct এর একটি ইনস্ট্যান্স গ্রহণ করে।
      • Rectangle(Rectangle): এটি Rectangle struct এর একটি ইনস্ট্যান্স গ্রহণ করে।
  3. Enum এবং Struct এর ব্যবহার:
    • shape1 এবং shape2 দুটি ভেরিয়েবল তৈরি করা হয়েছে, যেখানে একটি Circle এবং একটি Rectangle সংরক্ষিত রয়েছে।
    • match এক্সপ্রেশন ব্যবহার করে enum এর মান যাচাই করা হয়েছে এবং প্রতিটি আকৃতির প্রপার্টি প্রিন্ট করা হয়েছে।

কেন Enum এবং Struct একসাথে ব্যবহার করা?

  • লজিক্যাল সংগঠন: যখন আপনি বিভিন্ন ধরনের ডেটা গ্রুপ করতে চান, সেখানে enum ব্যবহার করা সুবিধাজনক। প্রতিটি enum ভ্যালু বিভিন্ন struct ধারণ করতে পারে, এবং এভাবে আমরা বিভিন্ন ধরনের ডেটাকে একত্রিত করতে পারি।
  • বিশেষ ফিচার যুক্ত করা: struct ডেটা ধারণের জন্য ব্যবহৃত হয়, যা জটিল বা বিশেষ ডেটা ধারণ করে। enum এর মাধ্যমে, আপনি একাধিক struct এর একটি ধরনের ডেটা গ্রুপ করতে পারেন এবং আলাদাভাবে প্রক্রিয়া করতে পারেন।
  • প্যাটার্ন ম্যাচিং: enum এবং struct এর কম্বিনেশন আপনাকে খুব সহজে match এক্সপ্রেশন ব্যবহার করে বিভিন্ন ধরনের অবজেক্ট চেক করার সুবিধা দেয়।

আরও উদাহরণ:

ধরা যাক, আমরা কিছু ব্যাংক একাউন্টের ধরন তৈরি করতে চাই। এর জন্য Account নামক enum এবং প্রতিটি অ্যাকাউন্টের জন্য struct ব্যবহার করতে পারি।

struct Savings {
    balance: f64,
    interest_rate: f64,
}

struct Checking {
    balance: f64,
    overdraft_limit: f64,
}

enum Account {
    Savings(Savings),
    Checking(Checking),
}

fn main() {
    let saving_account = Savings {
        balance: 5000.0,
        interest_rate: 2.5,
    };

    let checking_account = Checking {
        balance: 1000.0,
        overdraft_limit: 500.0,
    };

    let account1 = Account::Savings(saving_account);
    let account2 = Account::Checking(checking_account);

    match account1 {
        Account::Savings(s) => println!("Savings Account: Balance: {} with Interest Rate: {}", s.balance, s.interest_rate),
        Account::Checking(c) => println!("Checking Account: Balance: {} with Overdraft Limit: {}", c.balance, c.overdraft_limit),
    }

    match account2 {
        Account::Savings(s) => println!("Savings Account: Balance: {} with Interest Rate: {}", s.balance, s.interest_rate),
        Account::Checking(c) => println!("Checking Account: Balance: {} with Overdraft Limit: {}", c.balance, c.overdraft_limit),
    }
}

অংশবিশেষ:

  • Savings এবং Checking struct দুটি ব্যাংক একাউন্টের প্রপার্টি ধারণ করে।
  • Account enum এর মাধ্যমে, দুটি ভিন্ন ধরনের একাউন্টকে একত্রে গ্রুপ করা হয়েছে।
  • match এক্সপ্রেশন ব্যবহার করে ব্যাংক একাউন্টের বিভিন্ন প্রপার্টি চেক করা হয়েছে এবং আউটপুট দেওয়া হয়েছে।

সারাংশ

রাস্টে enum এবং struct এর কম্বিনেশন ব্যবহার করে আপনি আরও জটিল, গঠনমূলক এবং নমনীয় ডেটা মডেল তৈরি করতে পারেন। enum বিভিন্ন ধরনের অবজেক্টের গ্রুপিং করার জন্য ব্যবহৃত হয় এবং প্রতিটি অবজেক্টকে struct দিয়ে বিশদভাবে তৈরি করা যায়, যাতে প্রতিটি প্রপার্টি স্পষ্টভাবে ধারণ করা যায়। এর মাধ্যমে কোড আরও পরিষ্কার, শক্তিশালী এবং কার্যকরী হয়।

Content added By
Promotion

Are you sure to start over?

Loading...