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

Drop ট্রেইট ব্যবহার করে পরিচ্ছন্নতার সময় কোড রান করা

Smart pointer প্যাটার্নের জন্য গুরুত্বপূর্ণ দ্বিতীয় ট্রেইটটি হলো Drop, যা আপনাকে কাস্টমাইজ করতে দেয় যে একটি ভ্যালু স্কোপের বাইরে যাওয়ার সময় কী ঘটবে। আপনি যেকোনো টাইপের উপর Drop ট্রেইটের জন্য একটি ইমপ্লিমেন্টেশন প্রদান করতে পারেন, এবং সেই কোডটি ফাইল বা নেটওয়ার্ক সংযোগের মতো রিসোর্স মুক্ত করতে ব্যবহার করা যেতে পারে।

আমরা smart pointer-এর প্রেক্ষাপটে Drop ট্রেইটটি আলোচনা করছি কারণ একটি smart pointer ইমপ্লিমেন্ট করার সময় প্রায় সবসময়ই Drop ট্রেইটের কার্যকারিতা ব্যবহার করা হয়। উদাহরণস্বরূপ, যখন একটি Box<T> ড্রপ করা হয়, তখন এটি হিপ-এর সেই স্থানটি ডিঅ্যালোকেট করে যা বক্সটি নির্দেশ করে।

কিছু ভাষায়, কিছু নির্দিষ্ট টাইপের জন্য, প্রোগ্রামারকে প্রতিবার সেই টাইপের একটি ইনস্ট্যান্স ব্যবহার শেষ করার পরে মেমরি বা রিসোর্স মুক্ত করার জন্য কোড কল করতে হয়। এর উদাহরণ হলো ফাইল হ্যান্ডেল (file handles), সকেট (sockets) এবং লক (locks)। যদি তারা এটি করতে ভুলে যায়, সিস্টেম ওভারলোড হয়ে ক্র্যাশ করতে পারে। রাস্ট-এ, আপনি নির্দিষ্ট করতে পারেন যে একটি ভ্যালু স্কোপের বাইরে যাওয়ার সময় একটি নির্দিষ্ট কোড রান হবে, এবং কম্পাইলার এই কোডটি স্বয়ংক্রিয়ভাবে যোগ করে দেবে। ফলস্বরূপ, একটি প্রোগ্রামে যেখানে একটি নির্দিষ্ট টাইপের ইনস্ট্যান্সের কাজ শেষ হয়ে গেছে, সেখানে সর্বত্র পরিচ্ছন্নতার কোড রাখার বিষয়ে আপনাকে সতর্ক থাকতে হবে না—এবং আপনি রিসোর্স লিক করবেন না!

আপনি Drop ট্রেইট ইমপ্লিমেন্ট করে স্কোপের বাইরে যাওয়ার সময় চালানোর জন্য কোড নির্দিষ্ট করেন। Drop ট্রেইটের জন্য আপনাকে drop নামের একটি মেথড ইমপ্লিমেন্ট করতে হবে যা self-এর একটি mutable reference নেয়। রাস্ট কখন drop কল করে তা দেখতে, চলুন আপাতত println! স্টেটমেন্ট দিয়ে drop ইমপ্লিমেন্ট করি।

Listing 15-14 একটি CustomSmartPointer স্ট্রাকট দেখায় যার একমাত্র কাস্টম কার্যকারিতা হলো এটি Dropping CustomSmartPointer! প্রিন্ট করবে যখন ইনস্ট্যান্সটি স্কোপের বাইরে যাবে, এটি দেখানোর জন্য যে রাস্ট কখন drop মেথডটি রান করে।

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}

Drop ট্রেইটটি প্রিলিউডে (prelude) অন্তর্ভুক্ত, তাই আমাদের এটিকে স্কোপে আনার প্রয়োজন নেই। আমরা CustomSmartPointer-এর উপর Drop ট্রেইটটি ইমপ্লিমেন্ট করি এবং drop মেথডের জন্য একটি ইমপ্লিমেন্টেশন প্রদান করি যা println! কল করে। drop মেথডের বডি হলো সেই জায়গা যেখানে আপনি আপনার টাইপের একটি ইনস্ট্যান্স স্কোপের বাইরে যাওয়ার সময় চালাতে চান এমন যেকোনো লজিক রাখবেন। আমরা এখানে কিছু টেক্সট প্রিন্ট করছি যাতে দৃশ্যমানভাবে দেখানো যায় যে রাস্ট কখন drop কল করবে।

main-এ, আমরা CustomSmartPointer-এর দুটি ইনস্ট্যান্স তৈরি করি এবং তারপর CustomSmartPointers created. প্রিন্ট করি। main-এর শেষে, আমাদের CustomSmartPointer-এর ইনস্ট্যান্সগুলি স্কোপের বাইরে চলে যাবে, এবং রাস্ট drop মেথডে রাখা কোডটি কল করবে, আমাদের চূড়ান্ত বার্তাটি প্রিন্ট করবে। লক্ষ্য করুন যে আমাদের স্পষ্টভাবে drop মেথড কল করতে হয়নি।

যখন আমরা এই প্রোগ্রামটি রান করব, আমরা নিম্নলিখিত আউটপুট দেখতে পাব:

$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/drop-example`
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!

রাস্ট আমাদের জন্য স্বয়ংক্রিয়ভাবে drop কল করেছে যখন আমাদের ইনস্ট্যান্সগুলো স্কোপের বাইরে চলে গেছে, এবং আমাদের নির্দিষ্ট করা কোডটি কল করেছে। ভেরিয়েবলগুলো তাদের তৈরির বিপরীত ক্রমে ড্রপ করা হয়, তাই d কে c-এর আগে ড্রপ করা হয়েছে। এই উদাহরণের উদ্দেশ্য হলো drop মেথড কীভাবে কাজ করে তার একটি দৃশ্যমান ধারণা দেওয়া; সাধারণত আপনি একটি প্রিন্ট বার্তার পরিবর্তে আপনার টাইপের জন্য প্রয়োজনীয় পরিচ্ছন্নতার কোড নির্দিষ্ট করবেন।

std::mem::drop ব্যবহার করে কোনো ভ্যালু আগে ড্রপ করা

দুর্ভাগ্যবশত, স্বয়ংক্রিয় drop কার্যকারিতা নিষ্ক্রিয় করা সহজ নয়। drop নিষ্ক্রিয় করা সাধারণত প্রয়োজনীয় নয়; Drop ট্রেইটের মূল উদ্দেশ্যই হলো এটি স্বয়ংক্রিয়ভাবে যত্ন নেওয়া হয়। তবে, মাঝে মাঝে আপনি একটি ভ্যালু আগেভাগে পরিষ্কার করতে চাইতে পারেন। একটি উদাহরণ হলো যখন লক পরিচালনাকারী smart pointer ব্যবহার করা হয়: আপনি হয়তো লকটি ছেড়ে দেওয়ার জন্য drop মেথডটিকে জোর করে কল করতে চাইতে পারেন যাতে একই স্কোপের অন্য কোড লকটি অর্জন করতে পারে। রাস্ট আপনাকে Drop ট্রেইটের drop মেথড ম্যানুয়ালি কল করতে দেয় না; পরিবর্তে, যদি আপনি একটি ভ্যালুকে তার স্কোপ শেষ হওয়ার আগে ড্রপ করতে বাধ্য করতে চান তবে আপনাকে স্ট্যান্ডার্ড লাইব্রেরি দ্বারা প্রদত্ত std::mem::drop ফাংশনটি কল করতে হবে।

যদি আমরা Listing 15-14 থেকে main ফাংশনটি পরিবর্তন করে Drop ট্রেইটের drop মেথডটি ম্যানুয়ালি কল করার চেষ্টা করি, যেমনটি Listing 15-15-এ দেখানো হয়েছে, আমরা একটি কম্পাইলার এরর পাব।

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };
    println!("CustomSmartPointer created.");
    c.drop();
    println!("CustomSmartPointer dropped before the end of main.");
}

যখন আমরা এই কোডটি কম্পাইল করার চেষ্টা করব, আমরা এই এররটি পাব:

$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
  --> src/main.rs:16:7
   |
16 |     c.drop();
   |       ^^^^ explicit destructor calls not allowed
   |
help: consider using `drop` function
   |
16 |     drop(c);
   |     +++++ ~

For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` (bin "drop-example") due to 1 previous error

এই এরর বার্তাটি বলছে যে আমাদের স্পষ্টভাবে drop কল করার অনুমতি নেই। এরর বার্তাটিতে destructor শব্দটি ব্যবহার করা হয়েছে, যা একটি ইনস্ট্যান্স পরিষ্কার করার জন্য একটি ফাংশনের সাধারণ প্রোগ্রামিং পরিভাষা। একটি destructor একটি constructor-এর অনুরূপ, যা একটি ইনস্ট্যান্স তৈরি করে। রাস্টের drop ফাংশন একটি নির্দিষ্ট destructor।

রাস্ট আমাদের স্পষ্টভাবে drop কল করতে দেয় না কারণ রাস্ট main-এর শেষে ভ্যালুটির উপর স্বয়ংক্রিয়ভাবে drop কল করবে। এটি একটি double free এরর ঘটাবে কারণ রাস্ট একই ভ্যালু দুবার পরিষ্কার করার চেষ্টা করবে।

আমরা একটি ভ্যালু স্কোপের বাইরে যাওয়ার সময় drop-এর স্বয়ংক্রিয় সন্নিবেশ নিষ্ক্রিয় করতে পারি না, এবং আমরা স্পষ্টভাবে drop মেথড কল করতে পারি না। সুতরাং, যদি আমাদের একটি ভ্যালু আগেভাগে পরিষ্কার করতে বাধ্য করতে হয়, আমরা std::mem::drop ফাংশনটি ব্যবহার করি।

std::mem::drop ফাংশনটি Drop ট্রেইটের drop মেথড থেকে ভিন্ন। আমরা এটিকে আর্গুমেন্ট হিসাবে যে ভ্যালুটি জোর করে ড্রপ করতে চাই তা পাস করে কল করি। ফাংশনটি প্রিলিউডে রয়েছে, তাই আমরা Listing 15-15-এর main পরিবর্তন করে drop ফাংশনটি কল করতে পারি, যেমনটি Listing 15-16-এ দেখানো হয়েছে।

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };
    println!("CustomSmartPointer created.");
    drop(c);
    println!("CustomSmartPointer dropped before the end of main.");
}

এই কোডটি রান করলে নিম্নলিখিত প্রিন্ট হবে:

$ cargo run
   Compiling drop-example v0.1.0 (file:///projects/drop-example)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
     Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.

Dropping CustomSmartPointer with data `some data`! লেখাটি CustomSmartPointer created. এবং CustomSmartPointer dropped before the end of main. লেখার মধ্যে প্রিন্ট হয়েছে, যা দেখাচ্ছে যে drop মেথডের কোডটি সেই মুহূর্তে c-কে ড্রপ করার জন্য কল করা হয়েছে।

আপনি পরিচ্ছন্নতাকে সুবিধাজনক এবং নিরাপদ করতে একটি Drop ট্রেইট ইমপ্লিমেন্টেশনে নির্দিষ্ট করা কোড বিভিন্ন উপায়ে ব্যবহার করতে পারেন: উদাহরণস্বরূপ, আপনি এটি ব্যবহার করে আপনার নিজস্ব মেমরি অ্যালোকেটর তৈরি করতে পারেন! Drop ট্রেইট এবং রাস্টের ownership সিস্টেমের সাথে, আপনাকে পরিষ্কার করার কথা মনে রাখতে হবে না কারণ রাস্ট এটি স্বয়ংক্রিয়ভাবে করে।

আপনাকে ভুলবশত এখনও ব্যবহৃত ভ্যালু পরিষ্কার করার ফলে সৃষ্ট সমস্যা নিয়েও চিন্তা করতে হবে না: ownership সিস্টেম যা নিশ্চিত করে যে reference-গুলো সর্বদা বৈধ, সেটিই নিশ্চিত করে যে drop কেবল একবারই কল করা হয় যখন ভ্যালুটি আর ব্যবহৃত হচ্ছে না।

এখন যেহেতু আমরা Box<T> এবং smart pointer-এর কিছু বৈশিষ্ট্য পরীক্ষা করেছি, চলুন স্ট্যান্ডার্ড লাইব্রেরিতে সংজ্ঞায়িত আরও কয়েকটি smart pointer দেখি।