পরিশিষ্ট C: ডিরাইভেবল ট্রেইট (Derivable Traits)
বইয়ের বিভিন্ন স্থানে, আমরা derive
অ্যাট্রিবিউট নিয়ে আলোচনা করেছি, যা আপনি একটি স্ট্রাক্ট বা এনাম সংজ্ঞায় প্রয়োগ করতে পারেন। derive
অ্যাট্রিবিউট কোড তৈরি করে যা derive
সিনট্যাক্স দিয়ে আপনি যে টাইপটিকে অ্যানোটেট করেছেন তার উপর নিজস্ব ডিফল্ট ইমপ্লিমেন্টেশন সহ একটি ট্রেইট ইমপ্লিমেন্ট করবে।
এই পরিশিষ্টে, আমরা স্ট্যান্ডার্ড লাইব্রেরির সমস্ত ট্রেইটের একটি রেফারেন্স সরবরাহ করি যা আপনি derive
-এর সাথে ব্যবহার করতে পারেন। প্রতিটি বিভাগে কভার করা হয়েছে:
- এই ট্রেইট ডিরাইভ করলে কোন অপারেটর এবং মেথডগুলি সক্রিয় হবে
derive
দ্বারা প্রদত্ত ট্রেইটের ইমপ্লিমেন্টেশন কী করে- ট্রেইট ইমপ্লিমেন্ট করা টাইপ সম্পর্কে কী বোঝায়
- কোন পরিস্থিতিতে আপনাকে ট্রেইট ইমপ্লিমেন্ট করার অনুমতি দেওয়া হয়েছে বা নেই
- অপারেশনের উদাহরণ যার জন্য ট্রেইট প্রয়োজন
আপনি যদি derive
অ্যাট্রিবিউট দ্বারা প্রদত্ত আচরণ থেকে ভিন্ন আচরণ চান, তাহলে ম্যানুয়ালি কীভাবে সেগুলি ইমপ্লিমেন্ট করবেন তার বিশদ বিবরণের জন্য প্রতিটি ট্রেইটের জন্য স্ট্যান্ডার্ড লাইব্রেরি ডকুমেন্টেশন দেখুন।
এখানে তালিকাভুক্ত এই ট্রেইটগুলি হল স্ট্যান্ডার্ড লাইব্রেরি দ্বারা সংজ্ঞায়িত একমাত্র ট্রেইট যা derive
ব্যবহার করে আপনার টাইপগুলিতে ইমপ্লিমেন্ট করা যেতে পারে। স্ট্যান্ডার্ড লাইব্রেরিতে সংজ্ঞায়িত অন্যান্য ট্রেইটগুলির যুক্তিসঙ্গত ডিফল্ট আচরণ নেই, তাই আপনি যা অর্জন করার চেষ্টা করছেন তার জন্য উপযুক্ত উপায়ে সেগুলি ইমপ্লিমেন্ট করা আপনার উপর নির্ভর করে।
একটি ট্রেইটের উদাহরণ যা ডিরাইভ করা যায় না তা হল Display
, যা শেষ ব্যবহারকারীদের জন্য ফরম্যাটিং পরিচালনা করে। আপনার সর্বদা একজন শেষ ব্যবহারকারীর কাছে একটি টাইপ প্রদর্শনের উপযুক্ত উপায় বিবেচনা করা উচিত। টাইপের কোন অংশগুলি শেষ ব্যবহারকারীর দেখার অনুমতি দেওয়া উচিত? কোন অংশগুলি তারা প্রাসঙ্গিক বলে মনে করবে? ডেটার কোন ফরম্যাট তাদের জন্য সবচেয়ে প্রাসঙ্গিক হবে? Rust কম্পাইলারের এই অন্তর্দৃষ্টি নেই, তাই এটি আপনার জন্য উপযুক্ত ডিফল্ট আচরণ সরবরাহ করতে পারে না।
এই পরিশিষ্টে প্রদত্ত ডিরাইভেবল ট্রেইটগুলির তালিকা ব্যাপক নয়: লাইব্রেরিগুলি তাদের নিজস্ব ট্রেইটগুলির জন্য derive
ইমপ্লিমেন্ট করতে পারে, যার ফলে আপনি যে ট্রেইটগুলির সাথে derive
ব্যবহার করতে পারেন তার তালিকা সত্যিই উন্মুক্ত। derive
ইমপ্লিমেন্ট করার সাথে একটি প্রসিডিউরাল ম্যাক্রো ব্যবহার করা জড়িত, যা বিশ অধ্যায়ের “ম্যাক্রো” বিভাগে কভার করা হয়েছে।
প্রোগ্রামার আউটপুটের জন্য Debug
Debug
ট্রেইট ফরম্যাট স্ট্রিংগুলিতে ডিবাগ ফরম্যাটিং সক্রিয় করে, যা আপনি {}
প্লেসহোল্ডারগুলির মধ্যে :?
যোগ করে নির্দেশ করেন।
Debug
ট্রেইট আপনাকে ডিবাগিংয়ের উদ্দেশ্যে একটি টাইপের ইন্সট্যান্স প্রিন্ট করার অনুমতি দেয়, যাতে আপনি এবং আপনার টাইপ ব্যবহারকারী অন্যান্য প্রোগ্রামাররা প্রোগ্রামের এক্সিকিউশনের একটি নির্দিষ্ট পয়েন্টে একটি ইন্সট্যান্স পরিদর্শন করতে পারেন।
উদাহরণস্বরূপ, assert_eq!
ম্যাক্রো ব্যবহারে Debug
ট্রেইট প্রয়োজন। যদি সমতা অ্যাসারশন ব্যর্থ হয় তবে এই ম্যাক্রো আর্গুমেন্ট হিসাবে দেওয়া ইন্সট্যান্সগুলির ভ্যালু প্রিন্ট করে যাতে প্রোগ্রামাররা দেখতে পারে কেন দুটি ইন্সট্যান্স সমান ছিল না।
সমতা তুলনার জন্য PartialEq
এবং Eq
PartialEq
ট্রেইট আপনাকে সমতা পরীক্ষা করার জন্য একটি টাইপের ইন্সট্যান্সগুলির তুলনা করার অনুমতি দেয় এবং ==
এবং !=
অপারেটরগুলির ব্যবহার সক্রিয় করে।
PartialEq
ডিরাইভ করা eq
মেথড ইমপ্লিমেন্ট করে। যখন স্ট্রাক্টগুলিতে PartialEq
ডিরাইভ করা হয়, তখন দুটি ইন্সট্যান্স শুধুমাত্র তখনই সমান হয় যদি সমস্ত ফিল্ড সমান হয় এবং ইন্সট্যান্সগুলি সমান হয় না যদি কোনও ফিল্ড সমান না হয়। যখন এনামগুলিতে ডিরাইভ করা হয়, তখন প্রতিটি ভেরিয়েন্ট নিজের সাথে সমান এবং অন্য ভেরিয়েন্টগুলির সাথে সমান নয়।
উদাহরণস্বরূপ, assert_eq!
ম্যাক্রোর ব্যবহারের সাথে PartialEq
ট্রেইট প্রয়োজন, যেটি সমতার জন্য একটি টাইপের দুটি ইন্সট্যান্সের তুলনা করতে সক্ষম হওয়া প্রয়োজন।
Eq
ট্রেইটের কোনো মেথড নেই। এর উদ্দেশ্য হল সংকেত দেওয়া যে অ্যানোটেটেড টাইপের প্রতিটি ভ্যালুর জন্য, ভ্যালুটি নিজের সমান। Eq
ট্রেইট শুধুমাত্র সেই টাইপগুলিতে প্রয়োগ করা যেতে পারে যা PartialEq
ইমপ্লিমেন্ট করে, যদিও PartialEq
ইমপ্লিমেন্ট করে এমন সমস্ত টাইপ Eq
ইমপ্লিমেন্ট করতে পারে না। এর একটি উদাহরণ হল ফ্লোটিং পয়েন্ট নম্বর টাইপ: ফ্লোটিং পয়েন্ট সংখ্যার ইমপ্লিমেন্টেশন বলে যে নট-এ-নাম্বার (NaN
) ভ্যালুর দুটি ইন্সট্যান্স একে অপরের সমান নয়।
কখন Eq
প্রয়োজন তার একটি উদাহরণ হল HashMap<K, V>
-তে key-এর জন্য, যাতে HashMap<K, V>
বলতে পারে দুটি key একই কিনা।
অর্ডারিং তুলনার জন্য PartialOrd
এবং Ord
PartialOrd
ট্রেইট আপনাকে সর্টিংয়ের উদ্দেশ্যে একটি টাইপের ইন্সট্যান্সগুলির তুলনা করার অনুমতি দেয়। যে টাইপ PartialOrd
ইমপ্লিমেন্ট করে সেটি <
, >
, <=
, এবং >=
অপারেটরগুলির সাথে ব্যবহার করা যেতে পারে। আপনি শুধুমাত্র সেই টাইপগুলিতে PartialOrd
ট্রেইট প্রয়োগ করতে পারেন যা PartialEq
ইমপ্লিমেন্ট করে।
PartialOrd
ডিরাইভ করা partial_cmp
মেথড ইমপ্লিমেন্ট করে, যা একটি Option<Ordering>
রিটার্ন করে যা None
হবে যখন প্রদত্ত ভ্যালুগুলি কোনো অর্ডারিং তৈরি করে না। একটি ভ্যালুর উদাহরণ যা কোনো অর্ডারিং তৈরি করে না, যদিও সেই টাইপের বেশিরভাগ ভ্যালু তুলনা করা যায়, তা হল NaN
ফ্লোটিং পয়েন্ট ভ্যালু। যেকোনো ফ্লোটিং পয়েন্ট নম্বর এবং NaN
ফ্লোটিং পয়েন্ট ভ্যালু দিয়ে partial_cmp
কল করলে None
রিটার্ন করবে।
যখন স্ট্রাক্টগুলিতে ডিরাইভ করা হয়, তখন PartialOrd
স্ট্রাক্ট সংজ্ঞায় ফিল্ডগুলি যে ক্রমে প্রদর্শিত হয় সেই ক্রমে প্রতিটি ফিল্ডের ভ্যালু তুলনা করে দুটি ইন্সট্যান্সের তুলনা করে। যখন এনামগুলিতে ডিরাইভ করা হয়, তখন এনাম সংজ্ঞায় আগে ঘোষিত এনামের ভেরিয়েন্টগুলিকে পরে তালিকাভুক্ত ভেরিয়েন্টগুলির চেয়ে কম বলে মনে করা হয়।
উদাহরণস্বরূপ, rand
ক্রেট থেকে gen_range
মেথডের জন্য PartialOrd
ট্রেইট প্রয়োজন, যা একটি রেঞ্জ এক্সপ্রেশন দ্বারা নির্দিষ্ট করা রেঞ্জে একটি র্যান্ডম ভ্যালু জেনারেট করে।
Ord
ট্রেইট আপনাকে জানতে দেয় যে অ্যানোটেটেড টাইপের যেকোনো দুটি ভ্যালুর জন্য, একটি বৈধ অর্ডারিং বিদ্যমান থাকবে। Ord
ট্রেইট cmp
মেথড ইমপ্লিমেন্ট করে, যা একটি Option<Ordering>
-এর পরিবর্তে একটি Ordering
রিটার্ন করে কারণ একটি বৈধ অর্ডারিং সর্বদা সম্ভব হবে। আপনি শুধুমাত্র সেই টাইপগুলিতে Ord
ট্রেইট প্রয়োগ করতে পারেন যা PartialOrd
এবং Eq
ইমপ্লিমেন্ট করে (এবং Eq
-এর জন্য PartialEq
প্রয়োজন)। যখন স্ট্রাক্ট এবং এনামগুলিতে ডিরাইভ করা হয়, তখন cmp
, PartialOrd
-এর সাথে partial_cmp
-এর জন্য ডিরাইভ করা ইমপ্লিমেন্টেশনের মতোই আচরণ করে।
কখন Ord
প্রয়োজন তার একটি উদাহরণ হল BTreeSet<T>
-তে ভ্যালু সংরক্ষণ করার সময়, একটি ডেটা স্ট্রাকচার যা ভ্যালুগুলির সর্ট অর্ডারের উপর ভিত্তি করে ডেটা সংরক্ষণ করে।
ভ্যালু ডুপ্লিকেট করার জন্য Clone
এবং Copy
Clone
ট্রেইট আপনাকে একটি ভ্যালুর একটি ডিপ কপি তৈরি করার অনুমতি দেয় এবং ডুপ্লিকেশন প্রক্রিয়ায় নির্বিচারে কোড চালানো এবং হিপ ডেটা কপি করা জড়িত থাকতে পারে। Clone
সম্পর্কে আরও তথ্যের জন্য চতুর্থ অধ্যায়ের “ভেরিয়েবল এবং ডেটার সাথে ক্লোনের মিথস্ক্রিয়া” দেখুন।
Clone
ডিরাইভ করা clone
মেথড ইমপ্লিমেন্ট করে, যা সম্পূর্ণ টাইপের জন্য ইমপ্লিমেন্ট করা হলে, টাইপের প্রতিটি অংশে clone
কল করে। এর মানে হল Clone
ডিরাইভ করার জন্য টাইপের সমস্ত ফিল্ড বা ভ্যালুগুলিকে অবশ্যই Clone
ইমপ্লিমেন্ট করতে হবে।
কখন Clone
প্রয়োজন তার একটি উদাহরণ হল একটি স্লাইসে to_vec
মেথড কল করার সময়। স্লাইসটি এতে থাকা টাইপ ইন্সট্যান্সগুলির মালিক নয়, কিন্তু to_vec
থেকে রিটার্ন করা ভেক্টরটির তার ইন্সট্যান্সগুলির মালিক হতে হবে, তাই to_vec
প্রতিটি আইটেমে clone
কল করে। সুতরাং, স্লাইসে সংরক্ষিত টাইপটিকে অবশ্যই Clone
ইমপ্লিমেন্ট করতে হবে।
Copy
ট্রেইট আপনাকে শুধুমাত্র স্ট্যাকে সংরক্ষিত বিটগুলি কপি করে একটি ভ্যালু ডুপ্লিকেট করার অনুমতি দেয়; কোনো নির্বিচারে কোডের প্রয়োজন নেই। Copy
সম্পর্কে আরও তথ্যের জন্য চতুর্থ অধ্যায়ের “শুধুমাত্র স্ট্যাক ডেটা: কপি” দেখুন।
Copy
ট্রেইট প্রোগ্রামারদের সেই মেথডগুলিকে ওভারলোড করা এবং কোনও নির্বিচারে কোড চালানো হচ্ছে না সেই অনুমান লঙ্ঘন করা থেকে বিরত রাখতে কোনও মেথড সংজ্ঞায়িত করে না। এইভাবে, সমস্ত প্রোগ্রামার অনুমান করতে পারে যে একটি ভ্যালু কপি করা খুব দ্রুত হবে।
আপনি যেকোনো টাইপের উপর Copy
ডিরাইভ করতে পারেন যার সমস্ত অংশ Copy
ইমপ্লিমেন্ট করে। যে টাইপ Copy
ইমপ্লিমেন্ট করে তাকে অবশ্যই Clone
ইমপ্লিমেন্ট করতে হবে, কারণ যে টাইপ Copy
ইমপ্লিমেন্ট করে তার Clone
-এর একটি তুচ্ছ ইমপ্লিমেন্টেশন রয়েছে যা Copy
-এর মতোই কাজ করে।
Copy
ট্রেইট খুব কমই প্রয়োজন হয়; যে টাইপগুলি Copy
ইমপ্লিমেন্ট করে তাদের অপ্টিমাইজেশন উপলব্ধ থাকে, যার অর্থ আপনাকে clone
কল করতে হবে না, যা কোডটিকে আরও সংক্ষিপ্ত করে তোলে।
Copy
দিয়ে যা কিছু সম্ভব তা আপনি Clone
দিয়েও সম্পন্ন করতে পারেন, তবে কোডটি ধীর হতে পারে বা জায়গায় clone
ব্যবহার করতে হতে পারে।
একটি নির্দিষ্ট আকারের ভ্যালুতে একটি ভ্যালু ম্যাপ করার জন্য Hash
Hash
ট্রেইট আপনাকে নির্বিচারে আকারের একটি টাইপের ইন্সট্যান্স নিতে এবং একটি হ্যাশ ফাংশন ব্যবহার করে সেই ইন্সট্যান্সটিকে নির্দিষ্ট আকারের একটি ভ্যালুতে ম্যাপ করার অনুমতি দেয়। Hash
ডিরাইভ করা hash
মেথড ইমপ্লিমেন্ট করে। hash
মেথডের ডিরাইভ করা ইমপ্লিমেন্টেশন টাইপের প্রতিটি অংশে hash
কল করার ফলাফলকে একত্রিত করে, যার অর্থ Hash
ডিরাইভ করার জন্য সমস্ত ফিল্ড বা ভ্যালুগুলিকে অবশ্যই Hash
ইমপ্লিমেন্ট করতে হবে।
কখন Hash
প্রয়োজন তার একটি উদাহরণ হল ডেটা দক্ষতার সাথে সংরক্ষণ করার জন্য HashMap<K, V>
-তে key সংরক্ষণ করার সময়।
ডিফল্ট ভ্যালুর জন্য Default
Default
ট্রেইট আপনাকে একটি টাইপের জন্য একটি ডিফল্ট ভ্যালু তৈরি করার অনুমতি দেয়। Default
ডিরাইভ করা default
ফাংশন ইমপ্লিমেন্ট করে। default
ফাংশনের ডিরাইভ করা ইমপ্লিমেন্টেশন টাইপের প্রতিটি অংশে default
ফাংশন কল করে, যার অর্থ Default
ডিরাইভ করার জন্য টাইপের সমস্ত ফিল্ড বা ভ্যালুগুলিকে অবশ্যই Default
ইমপ্লিমেন্ট করতে হবে।
Default::default
ফাংশনটি সাধারণত পঞ্চম অধ্যায়ের “স্ট্রাক্ট আপডেট সিনট্যাক্স সহ অন্যান্য ইন্সট্যান্স থেকে ইন্সট্যান্স তৈরি করা” তে আলোচিত স্ট্রাক্ট আপডেট সিনট্যাক্সের সাথে ব্যবহার করা হয়। আপনি একটি স্ট্রাক্টের কয়েকটি ফিল্ড কাস্টমাইজ করতে পারেন এবং তারপর ..Default::default()
ব্যবহার করে বাকি ফিল্ডগুলির জন্য একটি ডিফল্ট ভ্যালু সেট এবং ব্যবহার করতে পারেন।
উদাহরণস্বরূপ, আপনি যখন Option<T>
ইন্সট্যান্সে unwrap_or_default
মেথড ব্যবহার করেন তখন Default
ট্রেইট প্রয়োজন। যদি Option<T>
None
হয়, তাহলে unwrap_or_default
মেথড Option<T>
-তে সংরক্ষিত টাইপ T
-এর জন্য Default::default
-এর ফলাফল রিটার্ন করবে।