Skill

Structures (স্ট্রাকচারস)

রাস্ট (Rust) - Computer Programming

441

স্ট্রাকচার (Structure) কী?

Rust-এ স্ট্রাকচার (structs) হল একটি ব্যবহারকারী-সংজ্ঞায়িত ডেটা টাইপ যা একাধিক ভ্যারিয়েবল বা প্রপার্টি (ফিল্ড) একত্রিত করে। স্ট্রাকচারগুলি একাধিক ধরনের ডেটা একত্রে ধারণ করতে সক্ষম, এবং এর মাধ্যমে একটি জটিল ডেটা সেট তৈরি করা যায়।

স্ট্রাকচারগুলি বিশেষভাবে ব্যবহৃত হয় যখন আমাদের একাধিক ডেটা একত্রে রাখার প্রয়োজন হয়, যেমন একটি "ব্যক্তি" বা "পণ্য" যার মধ্যে বিভিন্ন ধরনের তথ্য থাকতে পারে (যেমন নাম, বয়স, মূল্য ইত্যাদি)।


স্ট্রাকচার ডিফাইন করা

Rust-এ একটি স্ট্রাকচার ডিফাইন করতে struct কীওয়ার্ড ব্যবহার করা হয়।

স্ট্রাকচার ডিফাইন করার সাধারণ Syntax:

struct Person {
    name: String,
    age: u32,
}

উপরের কোডে:

  • Person একটি স্ট্রাকচার যার মধ্যে দুটি ফিল্ড রয়েছে: name (যার টাইপ String) এবং age (যার টাইপ u32)।

স্ট্রাকচারের ইনস্ট্যান্স তৈরি

স্ট্রাকচার ডিফাইন করার পর, আমরা স্ট্রাকচারের নতুন ইনস্ট্যান্স তৈরি করতে পারি।

স্ট্রাকচার ইনস্ট্যান্স তৈরি করার Syntax:

let person1 = Person {
    name: String::from("Alice"),
    age: 30,
};

এখানে person1 হল Person স্ট্রাকচারের একটি ইনস্ট্যান্স, যেখানে name এবং age ফিল্ডের মান দেওয়া হয়েছে।


স্ট্রাকচারের ফিল্ড অ্যাক্সেস করা

স্ট্রাকচারের মধ্যে রাখা ডেটা অ্যাক্সেস করতে, আপনি ডট নোটেশন ব্যবহার করতে পারেন।

ফিল্ড অ্যাক্সেসের Syntax:

println!("Name: {}, Age: {}", person1.name, person1.age);

এখানে person1.name এবং person1.age দিয়ে Person স্ট্রাকচারের ফিল্ডে রাখা ডেটা অ্যাক্সেস করা হয়েছে।


স্ট্রাকচার ফাংশন (Methods)

স্ট্রাকচারে ফাংশনও ডিফাইন করা যেতে পারে। Rust-এ স্ট্রাকচারের ফাংশনগুলি method নামে পরিচিত এবং এগুলি সাধারণত impl ব্লকের মধ্যে ডিফাইন করা হয়।

স্ট্রাকচার মেথড ডিফাইন করার Syntax:

impl Person {
    fn greet(&self) {
        println!("Hello, my name is {} and I am {} years old.", self.name, self.age);
    }
}

এখানে greet নামের একটি method Person স্ট্রাকচারের জন্য ডিফাইন করা হয়েছে, যা self রেফারেন্স ব্যবহার করে স্ট্রাকচারের ফিল্ডে অ্যাক্সেস পায়।

মেথড কল করার Syntax:

person1.greet();

এটি greet মেথড কল করবে এবং কনসোলে Hello, my name is Alice and I am 30 years old. প্রিন্ট হবে।


স্ট্রাকচারে মিউটেবল ফিল্ডস

যদি আপনি স্ট্রাকচারে কোনো ফিল্ড মিউটেবল করতে চান, তাহলে সেই স্ট্রাকচারের ইনস্ট্যান্সকেও মিউটেবল হতে হবে। অর্থাৎ, আপনাকে mut কীওয়ার্ড ব্যবহার করতে হবে।

স্ট্রাকচারের মিউটেবল ফিল্ড আপডেট করার Syntax:

let mut person2 = Person {
    name: String::from("Bob"),
    age: 25,
};

person2.age = 26;  // মিউটেবল ফিল্ড আপডেট করা
println!("Updated Age: {}", person2.age);

এখানে mut ব্যবহারের মাধ্যমে person2 কে মিউটেবল করা হয়েছে, যাতে age ফিল্ড পরিবর্তন করা যায়।


স্ট্রাকচারের টুপল স্টাইল (Tuple-style structs)

Rust-এ আপনি স্ট্রাকচার ডিফাইন করার আরও একটি স্টাইল ব্যবহার করতে পারেন, যা টুপল স্টাইল (tuple-style) নামে পরিচিত। এই স্টাইলের মধ্যে ফিল্ডগুলোর নাম দেয়া হয় না, বরং তারা একটি নির্দিষ্ট অর্ডারে থাকে।

টুপল স্টাইল স্ট্রাকচারের উদাহরণ:

struct Color(i32, i32, i32);

let color1 = Color(255, 0, 0);  // রেড রঙ
println!("Red: {}, Green: {}, Blue: {}", color1.0, color1.1, color1.2);

এখানে Color স্ট্রাকচারটি একটি টুপল স্টাইল স্ট্রাকচার, যার তিনটি উপাদান রয়েছে: i32 টাইপের তিনটি মান। টুপল স্টাইল স্ট্রাকচারে, ফিল্ডগুলোকে ডট নোটেশন দিয়ে অ্যাক্সেস করা হয়, যেমন color1.0, color1.1, এবং color1.2


সারাংশ

Rust-এ স্ট্রাকচারস খুবই গুরুত্বপূর্ণ এবং শক্তিশালী ডেটা ধারণা যা বিভিন্ন ধরনের তথ্য একত্রে রাখতে সহায়তা করে। স্ট্রাকচার ডিফাইন করা, ইনস্ট্যান্স তৈরি করা, এবং তাদের মেথড ব্যবহার করার মাধ্যমে আপনি ডেটা ম্যানিপুলেশনকে আরও সহজ করতে পারেন। Rust-এ স্ট্রাকচারস কেবল ডেটা সংরক্ষণে নয়, বরং সিস্টেমের লজিক এবং আচরণ (behaviors) তৈরি করতে সাহায্য করে।

Content added By

Structs কী?

রাস্টে struct (স্ট্রাক্ট) হল একটি কাস্টম ডেটা টাইপ যা এক বা একাধিক ভ্যালু (ফিল্ড) ধারণ করতে পারে। স্ট্রাক্টের মাধ্যমে আপনি সম্পর্কিত ডেটা একত্রে গ্রুপ করতে পারেন, যা কোডকে আরও সংগঠিত এবং রক্ষণাবেক্ষণযোগ্য করে তোলে।

স্ট্রাক্ট হল সাধারণত ডেটা-কন্টেইনার যেগুলো ভেরিয়েবল ও ডেটার গ্রুপ হিসাবে ব্যবহৃত হয়। এটি ঐতিহ্যগতভাবে অন্যান্য ভাষায় ক্লাস এর মতো কাজ করে, তবে এটি সি বা সি++ এর মতো ভাষায় কমপ্লেক্স ক্লাস স্ট্রাকচারের বিকল্প।

স্ট্রাক্ট ডিফাইন করা (Defining a Struct)

রাস্টে স্ট্রাক্ট ডিফাইন করার জন্য struct কিওয়ার্ড ব্যবহার করা হয়। স্ট্রাক্টের ভিতরে বিভিন্ন ধরনের ডেটা টাইপ ধারণ করা যেতে পারে, যেমন ইন্টিজার, স্ট্রিং, বুলিয়ান ইত্যাদি।

স্ট্রাক্ট ডিফাইন করার উদাহরণ:

struct Person {
    name: String,
    age: u32,
}

এখানে Person নামের একটি স্ট্রাক্ট ডিফাইন করা হয়েছে যা দুটি ফিল্ড ধারণ করে: name (যেটি String টাইপের) এবং age (যেটি u32 টাইপের)।

স্ট্রাক্ট ইন্সট্যান্স তৈরি করা (Creating an Instance of a Struct)

স্ট্রাক্টের ইন্সট্যান্স তৈরি করতে, স্ট্রাক্টের নাম লিখে এবং ফিল্ডগুলির মান দিতে হয়।

উদাহরণ:

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };
    println!("Name: {}, Age: {}", person1.name, person1.age);
}

এখানে person1 একটি স্ট্রাক্টের ইন্সট্যান্স, যেখানে name ফিল্ডে "Alice" এবং age ফিল্ডে 30 প্রদান করা হয়েছে। এইভাবে স্ট্রাক্টের মান অ্যাক্সেস করা যায়।

struct এর methods (স্ট্রাক্টের মেথডস)

রাস্টে স্ট্রাক্টে মেথড যোগ করা যেতে পারে, যা স্ট্রাক্টের ডেটার সাথে কাজ করে। স্ট্রাক্টের মেথডগুলোকে সাধারণত impl (implementation) ব্লকে ডিফাইন করা হয়।

উদাহরণ:

struct Person {
    name: String,
    age: u32,
}

impl Person {
    fn greet(&self) {
        println!("Hello, my name is {} and I am {} years old.", self.name, self.age);
    }

    fn is_adult(&self) -> bool {
        self.age >= 18
    }
}

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };
    
    person1.greet();
    
    if person1.is_adult() {
        println!("{} is an adult.", person1.name);
    } else {
        println!("{} is not an adult.", person1.name);
    }
}

এখানে Person স্ট্রাক্টের জন্য দুটি মেথড রয়েছে:

  • greet(): এটি name এবং age ফিল্ড ব্যবহার করে একটি স্বাগতম বার্তা প্রিন্ট করে।
  • is_adult(): এটি age ফিল্ড চেক করে যে ব্যক্তি বড় (১৮ বছর বা তার বেশি) কিনা।

&self অর্থাৎ স্ট্রাক্টের বর্তমান ইন্সট্যান্সটিকে মেথডের মধ্যে পাঠানো হয়, যা স্ট্রাক্টের ডেটার উপর কাজ করতে সক্ষম হয়।

স্ট্রাক্টের ডিফল্ট মান (Default Values for Structs)

রাস্টে আপনি স্ট্রাক্টের জন্য ডিফল্ট মানও নির্ধারণ করতে পারেন, যদি আপনি স্ট্রাক্টটি নির্মাণ করার সময় কিছু ফিল্ডের জন্য মান না দেন।

উদাহরণ:

#[derive(Default)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        ..Default::default()  // বাকি ফিল্ডগুলো ডিফল্ট মান নেবে
    };
    println!("Name: {}, Age: {}", person1.name, person1.age);
}

এখানে Default ট্রেইট (derive দিয়ে) ব্যবহার করে স্ট্রাক্টের ডিফল্ট মান নির্ধারণ করা হয়েছে। আপনি শুধু name সেট করছেন, এবং age ফিল্ডটি ডিফল্ট মান (যেমন 0) নিবে।

স্ট্রাক্টের আংশিক আপডেট (Partial Updates)

রাস্টে স্ট্রাক্টের একটি ইন্সট্যান্স তৈরি করার সময়, আপনি কিছু ফিল্ড আপডেট করতে পারেন এবং বাকি ফিল্ডগুলি আগের মান থেকে রেখে দিতে পারেন।

উদাহরণ:

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };

    let person2 = Person {
        age: 35, // শুধু age আপডেট করা হয়েছে
        ..person1  // বাকি ফিল্ড গুলি person1 থেকে আসবে
    };

    println!("Name: {}, Age: {}", person2.name, person2.age);
}

এখানে person1 থেকে person2 তৈরি করার সময় শুধু age আপডেট করা হয়েছে, আর বাকি ফিল্ডগুলি person1 এর মান নিয়েছে।

Tuple Structs (টিউপল স্ট্রাক্ট)

রাস্টে আপনি tuple structsও তৈরি করতে পারেন, যেখানে ফিল্ডগুলোর নাম থাকে না, শুধুমাত্র তাদের অর্ডার থাকে। এগুলো সাধারণ স্ট্রাক্টের মতোই কাজ করে, তবে ফিল্ডের নামের পরিবর্তে ইনডেক্স ব্যবহার করা হয়।

উদাহরণ:

struct Color(i32, i32, i32);

fn main() {
    let black = Color(0, 0, 0);
    println!("Black color: {}, {}, {}", black.0, black.1, black.2);
}

এখানে Color একটি টিউপল স্ট্রাক্ট, যা তিনটি i32 মান ধারণ করে। ফিল্ডগুলো black.0, black.1 এবং black.2 দিয়ে অ্যাক্সেস করা হয়।

সারাংশ

রাস্টে স্ট্রাক্টস ডেটার সংগঠন এবং পরিচালনার জন্য একটি শক্তিশালী পদ্ধতি। এটি সম্পর্কিত ডেটাকে একত্রে গ্রুপ করতে এবং কোডের পুনঃব্যবহারযোগ্যতা ও সুসংগঠন নিশ্চিত করতে সাহায্য করে। স্ট্রাক্টের মাধ্যমে আপনি উন্নত ডেটা মডেল তৈরি করতে পারেন এবং মেথড ব্যবহার করে কোডের কার্যকারিতা বৃদ্ধি করতে পারেন।

Content added By

Tuple Structs

রাস্টে Tuple Structs একটি ধরনের struct (স্ট্রাক্ট) যা সাধারণত একটি নির্দিষ্ট কাঠামোর সাথে ডেটা ধারণ করতে ব্যবহৃত হয়, কিন্তু এখানে ফিল্ডগুলির নাম দেওয়া হয় না, শুধু তাদের অবস্থান (position) অনুযায়ী ব্যবহৃত হয়। এটি একটি সাধারণ ধরনের স্ট্রাক্ট, যেখানে ফিল্ডগুলি অর্ডার অনুযায়ী অ্যাক্সেস করা হয়।

Tuple Structs এর সাধারণ কাঠামো:

struct MyStruct(i32, f64, char);

এখানে, MyStruct একটি tuple struct যা তিনটি ভেরিয়েবল ধারণ করে: একটি পূর্ণসংখ্যা (i32), একটি ফ্লোটিং-পয়েন্ট সংখ্যা (f64), এবং একটি চরিত্র (char)।

Tuple Struct এর উদাহরণ:

// Tuple struct ডিক্লেয়ার করা
struct MyStruct(i32, f64, char);

fn main() {
    // Tuple struct এর ইনস্ট্যান্স তৈরি করা
    let instance = MyStruct(10, 3.14, 'a');

    // Tuple struct এর ফিল্ড অ্যাক্সেস করা
    println!("First: {}, Second: {}, Third: {}", instance.0, instance.1, instance.2);
}

এখানে, instance.0 প্রথম ফিল্ড (i32), instance.1 দ্বিতীয় ফিল্ড (f64), এবং instance.2 তৃতীয় ফিল্ড (char) অ্যাক্সেস করেছে।

বিশেষত্ব:

  • Tuple Structs সাধারণত দ্রুত, ছোট এবং সহজ ডেটা কাঠামোতে ব্যবহৃত হয়।
  • এটি সেই সব ক্ষেত্রে ভাল যেখানে ফিল্ডগুলির নামের চেয়ে তাদের অবস্থান গুরুত্বপূর্ণ।

Named Structs

Named Structs একটি স্ট্রাক্ট যার প্রতিটি ফিল্ডের একটি নির্দিষ্ট নাম থাকে। এখানে ফিল্ডের নাম স্পষ্টভাবে ডিফাইন করা হয়, যা কোডের পাঠযোগ্যতা এবং সঠিক ফিল্ড অ্যাক্সেস নিশ্চিত করে। এটি ব্যবহারকারীদের জন্য আরও বেশি কার্যকরী, বিশেষত যখন আপনি একটি বৃহৎ ডেটা কাঠামো পরিচালনা করছেন।

Named Structs এর সাধারণ কাঠামো:

struct MyStruct {
    x: i32,
    y: f64,
    z: char,
}

এখানে, MyStruct একটি named struct, যার মধ্যে তিনটি ফিল্ড রয়েছে: x, y, এবং z। প্রতিটি ফিল্ডের নাম স্পষ্টভাবে উল্লেখ করা হয়েছে।

Named Struct এর উদাহরণ:

// Named struct ডিক্লেয়ার করা
struct MyStruct {
    x: i32,
    y: f64,
    z: char,
}

fn main() {
    // Named struct এর ইনস্ট্যান্স তৈরি করা
    let instance = MyStruct { x: 10, y: 3.14, z: 'a' };

    // Named struct এর ফিল্ড অ্যাক্সেস করা
    println!("x: {}, y: {}, z: {}", instance.x, instance.y, instance.z);
}

এখানে, instance.x, instance.y, এবং instance.z এর মাধ্যমে স্ট্রাক্টের ফিল্ডগুলি অ্যাক্সেস করা হয়েছে।

বিশেষত্ব:

  • Named Structs ফিল্ডগুলির নাম স্পষ্টভাবে ডিফাইন করার জন্য ব্যবহৃত হয়, যা কোডকে আরও পাঠযোগ্য এবং বোধগম্য করে তোলে।
  • এটি বৃহৎ অ্যাপ্লিকেশন বা ডেটা কাঠামোর ক্ষেত্রে উপযোগী, যেখানে ফিল্ডের নামের মাধ্যমে ডেটার অর্থ বা উদ্দেশ্য বোঝানো হয়।

Tuple Structs এবং Named Structs এর মধ্যে পার্থক্য

বিষয়Tuple StructsNamed Structs
ফিল্ডের নামফিল্ডগুলির নাম থাকে না; শুধুমাত্র অবস্থান (index) অনুযায়ী অ্যাক্সেস করা হয়।প্রতিটি ফিল্ডের একটি নাম থাকে।
ব্যবহারছোট এবং সহজ ডেটা কাঠামোর জন্য ব্যবহৃত হয়।বৃহৎ এবং জটিল ডেটা কাঠামোর জন্য ব্যবহৃত হয়।
ফিল্ড অ্যাক্সেসফিল্ডগুলি তাদের ইনডেক্স দ্বারা অ্যাক্সেস করা হয় (যেমন instance.0)।ফিল্ডগুলি তাদের নাম দ্বারা অ্যাক্সেস করা হয় (যেমন instance.x)।
উদাহরণstruct MyStruct(i32, f64, char);struct MyStruct { x: i32, y: f64, z: char };

সারাংশ

রাস্টে Tuple Structs এবং Named Structs এর মধ্যে প্রধান পার্থক্য হল, যেখানে Tuple Structs শুধুমাত্র ডেটার অবস্থান অনুযায়ী কাজ করে, Named Structs ফিল্ডগুলির নাম স্পষ্টভাবে উল্লেখ করে। Tuple Structs সহজ এবং ছোট ডেটা কাঠামোর জন্য উপযুক্ত, এবং Named Structs বৃহৎ, জটিল বা বিশদ ডেটা কাঠামোর জন্য উপযুক্ত যেখানে ফিল্ডের নাম গুরুত্বপূর্ণ।

Content added By

Struct কী?

রাস্টে struct (স্ট্রাকচার) একটি কাস্টম ডেটা টাইপ যা এক বা একাধিক ফিল্ড ধারণ করতে পারে। এটি একত্রে বিভিন্ন প্রপার্টি বা ভেরিয়েবল গ্রুপ করতে ব্যবহার করা হয়। স্ট্রাকচারগুলির মধ্যে মেথড ডিফাইন করা সম্ভব, যা স্ট্রাকচারের ডেটা বা ফিল্ডের সাথে কাজ করে।


Struct এ মেথড ডিফাইন করা

স্ট্রাকচারের জন্য মেথড ডিফাইন করার জন্য, আপনাকে একটি impl ব্লক ব্যবহার করতে হবে। impl ব্লক স্ট্রাকচারের জন্য মেথড এবং অ্যাসোসিয়েটেড ফাংশন সংজ্ঞায়িত করে।

মেথডের ডিফাইনেশন

স্ট্রাকচারের মেথড ডিফাইন করতে impl ব্লক ব্যবহার করা হয়, এবং মেথডের প্রথম প্যারামিটার হিসাবে &self ব্যবহার করা হয়। self হল স্ট্রাকচারের ইন্সট্যান্স (অথবা বস্তু) যা মেথডটিকে অ্যাক্সেস করতে সাহায্য করে।

উদাহরণ:

// স্ট্রাকচার ডিফাইন করা
struct Circle {
    radius: f64,
}

// স্ট্রাকচারের মেথড ডিফাইন করা
impl Circle {
    // মেথড যা 'self' ব্যবহার করে স্ট্রাকচারের ডেটা অ্যাক্সেস করে
    fn area(&self) -> f64 {
        3.14 * self.radius * self.radius
    }

    // মেথড যা 'self' ব্যবহার করে স্ট্রাকচারের ডেটা পরিবর্তন করতে সক্ষম
    fn set_radius(&mut self, radius: f64) {
        self.radius = radius;
    }
}

fn main() {
    let mut circle = Circle { radius: 5.0 };  // স্ট্রাকচার ইনস্ট্যান্স তৈরি

    // মেথড কল করা
    println!("Area: {}", circle.area());  // স্ট্রাকচারের 'area' মেথড ব্যবহার
    circle.set_radius(10.0);               // স্ট্রাকচারের 'set_radius' মেথড ব্যবহার
    println!("New Area: {}", circle.area());
}

মেথডের বিস্তারিত ব্যাখ্যা:

  1. area(&self) মেথড:
    • এটি স্ট্রাকচারের radius ফিল্ডের মান নিয়ে একটি হিসাব করে সার্কেলের এলাকা (area) রিটার্ন করে। &self মানে এটি স্ট্রাকচারের অবস্থা (অথবা ডেটা) পড়তে পারে কিন্তু সেটি পরিবর্তন করতে পারে না (এটা immutable রেফারেন্স)।
  2. set_radius(&mut self, radius: f64) মেথড:
    • এই মেথডটি স্ট্রাকচারের radius ফিল্ড পরিবর্তন করতে সক্ষম। এখানে &mut self ব্যবহার করা হয়েছে, যার মানে হলো এই মেথডটি স্ট্রাকচারের অবস্থা পরিবর্তন করতে পারে (mutable রেফারেন্স)।

Associated Functions (অ্যাসোসিয়েটেড ফাংশন)

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

উদাহরণ:

impl Circle {
    // অ্যাসোসিয়েটেড ফাংশন (যে কোন 'self' প্যারামিটার নেই)
    fn new(radius: f64) -> Circle {
        Circle { radius }
    }
}

fn main() {
    let circle = Circle::new(5.0); // অ্যাসোসিয়েটেড ফাংশন ব্যবহার
    println!("Area: {}", circle.area());
}

এখানে, new ফাংশনটি Circle স্ট্রাকচারের একটি নতুন ইনস্ট্যান্স তৈরি করে। এটি একটি অ্যাসোসিয়েটেড ফাংশন, কারণ এটি স্ট্রাকচারের সাথে সম্পর্কিত, কিন্তু এটি self প্যারামিটার ব্যবহার করে না।


সারাংশ

রাস্টে স্ট্রাকচারের মধ্যে মেথড ডিফাইন করতে impl ব্লক ব্যবহার করা হয়। মেথডগুলির প্রথম প্যারামিটার হিসেবে self ব্যবহার করে স্ট্রাকচারের ফিল্ড অ্যাক্সেস করা হয়, এবং আপনি যদি ফিল্ড পরিবর্তন করতে চান তবে &mut self ব্যবহার করতে হবে। এছাড়া, অ্যাসোসিয়েটেড ফাংশন গুলি self ছাড়া স্ট্রাকচারের সাথে সম্পর্কিত কার্যাবলী সম্পাদন করে।

Content added By

Structs (স্ট্রাক্টস)

স্ট্রাক্টস হল একটি ব্যবহারকারী-সংজ্ঞায়িত ডেটা টাইপ যা একাধিক ডেটা ফিল্ড ধারণ করতে পারে। এটি সাধারণত সম্পর্কিত ডেটা একটি ইউনিটের মধ্যে গ্রুপ করার জন্য ব্যবহৃত হয়। স্ট্রাক্টস রাস্টের মধ্যে খুবই শক্তিশালী এবং এটি সাধারণত অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং এর মতো ধারণা গঠন করতে সাহায্য করে।

স্ট্রাক্টস তৈরি করা:

স্ট্রাক্ট তৈরি করতে struct কীওয়ার্ড ব্যবহার করা হয়।

উদাহরণ:

struct Person {
    name: String,
    age: u32,
}

fn main() {
    // একটি Person স্ট্রাক্ট তৈরি
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };

    println!("Name: {}, Age: {}", person1.name, person1.age);
}

এখানে Person একটি স্ট্রাক্ট যা name এবং age নামে দুটি ফিল্ড ধারণ করছে।

স্ট্রাক্টে ফাংশন যোগ করা:

স্ট্রাক্টে ফাংশন যোগ করতে impl ব্লক ব্যবহার করা হয়, যেখানে স্ট্রাক্টের জন্য ফাংশন বা মেথড সংজ্ঞায়িত করা হয়।

উদাহরণ:

impl Person {
    fn greet(&self) {
        println!("Hello, my name is {}", self.name);
    }
}

fn main() {
    let person1 = Person {
        name: String::from("Bob"),
        age: 25,
    };
    person1.greet();
}

এখানে greet মেথড স্ট্রাক্ট Person এর জন্য তৈরি করা হয়েছে, যা self রেফারেন্স ব্যবহার করে name প্রপার্টি অ্যাক্সেস করে।


Ownership (অনারশিপ)

রাস্টের Ownership মডেলটি মেমোরি ম্যানেজমেন্টকে গ্যারান্টি দেওয়ার জন্য অত্যন্ত গুরুত্বপূর্ণ। এই মডেলটি ownership, borrowing, এবং lifetime এর ধারণার মাধ্যমে পরিচালিত হয় এবং মেমোরি সেফটি নিশ্চিত করে, যেখানে গ্যারবেজ কালেক্টর ছাড়াই মেমোরি ম্যানেজ করা সম্ভব।

Ownership এর তিনটি মূল নিয়ম:

  1. একটি ভেরিয়েবল শুধুমাত্র একটি মালিক থাকতে পারে:
    একটি ভেরিয়েবল যখন একটি মান ধারণ করে, তখন সেই মানের মালিক সেই ভেরিয়েবল। মালিকানা যখন অন্য ভেরিয়েবলে স্থানান্তরিত হয়, তখন আগের ভেরিয়েবল আর সেই মানের মালিক থাকে না।
  2. বোরোউ (Borrowing):
    মালিকানা পরিবর্তন না করে, অন্য ভেরিয়েবল বা ফাংশনকে ডেটা আংশিকভাবে অ্যাক্সেস করার অনুমতি দেওয়া হয়। এটি immutable borrow (শুধু পড়া) এবং mutable borrow (লেখা এবং পড়া) হিসেবে বিভক্ত করা হয়। কিন্তু এক সময়ে শুধুমাত্র একটি mutable borrow থাকতে পারে, বা একাধিক immutable borrow থাকতে পারে, কিন্তু একসাথে দুটি থাকতে পারে না।
  3. মেমোরি রিলিজ:
    যখন মালিক ভেরিয়েবল ড্রপ হয় (scope শেষ হলে), তখন ওই ভেরিয়েবলের মেমোরি স্বয়ংক্রিয়ভাবে মুক্ত হয়ে যায়। এটি গ্যারান্টি দেয় যে, আপনি কখনও মেমোরি লিক বা ডাবল ফ্রি করতে পারবেন না।

Ownership এর উদাহরণ:

উদাহরণ ১: Ownership (মালিকানা স্থানান্তর)

fn main() {
    let s1 = String::from("Hello");  // s1 মালিক
    let s2 = s1;                      // s1 থেকে s2 তে মালিকানা স্থানান্তর

    // println!("{}", s1); // এই লাইনটি কম্পাইল হবে না, কারণ s1 এর মালিকানা s2 তে চলে গেছে।
    println!("{}", s2);   // এটা ঠিক আছে
}

এখানে s1 থেকে s2 তে মালিকানা স্থানান্তরিত হচ্ছে, এবং এর ফলে s1 আর ব্যবহারযোগ্য থাকে না।

উদাহরণ ২: Immutable Borrow (ইমিউটেবল বোরোউ)

fn main() {
    let s1 = String::from("Hello");
    let s2 = &s1; // s1 এর immutable borrow

    println!("{}", s1);  // এটা ঠিক আছে, কারণ s2 শুধুমাত্র পড়ছে
    println!("{}", s2);
}

এখানে s2 s1 থেকে একটি immutable borrow নিয়েছে, তাই s1 এখনো ব্যবহৃত হতে পারে।

উদাহরণ ৩: Mutable Borrow (মিউটেবল বোরোউ)

fn main() {
    let mut s1 = String::from("Hello");
    let s2 = &mut s1;  // mutable borrow

    s1.push_str(", World!");  // কম্পাইল হবে না, কারণ s1 এর mutable borrow করা হয়েছে

    println!("{}", s2);  // এটি কম্পাইল হবে না, কারণ s1 এখন mutable borrowed রয়েছে
}

এখানে s1 এর mutable borrow করা হয়েছে, ফলে অন্য কোনো mutable বা immutable borrow করা যাবে না।


Ownership এবং Structs

স্ট্রাক্টসেও Ownership এর নিয়মগুলো কার্যকরী। যখন একটি স্ট্রাক্টে ডেটা স্থানান্তর করা হয়, তখন তার ফিল্ডগুলোও মালিকানা স্থানান্তরিত হয়।

উদাহরণ:

struct Person {
    name: String,
    age: u32,
}

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };

    let person2 = person1;  // person1 থেকে person2 তে মালিকানা স্থানান্তরিত

    // println!("{}", person1.name);  // এই লাইনটি কম্পাইল হবে না, কারণ person1 এর মালিকানা person2 তে চলে গেছে
    println!("{}", person2.name);  // ঠিক আছে
}

এখানে person1 থেকে person2 তে মালিকানা স্থানান্তরিত হয়ে গেছে, এবং person1 এখন আর ব্যবহৃত হতে পারে না।


সারাংশ

  • Structs একটি ব্যবহারকারী-সংজ্ঞায়িত ডেটা টাইপ যা একাধিক মান বা ফিল্ড ধারণ করে।
  • Ownership একটি গুরুত্বপূর্ণ বৈশিষ্ট্য যা মেমোরি সেফটি নিশ্চিত করে, যেখানে এক সময় একটি ডেটার শুধুমাত্র একটি মালিক থাকে।
  • মালিকানা স্থানান্তরিত হলে আগের মালিক আর ডেটা অ্যাক্সেস করতে পারে না।
  • Borrowing পদ্ধতি মালিকানা পরিবর্তন না করেই ডেটা শেয়ার করতে সহায়তা করে, তবে একসাথে একাধিক mutable borrow হতে পারে না।
  • মালিকানা নিয়ম অনুসারে, স্ট্রাক্টসের ক্ষেত্রেও মালিকানা স্থানান্তরিত হয়।
Content added By
Promotion

Are you sure to start over?

Loading...