অনেক সময় কিছু আইটেমকে একসাথে একটি দলে ভাগ করা এবং সেই দলগুলোকে একক হিসেবে ব্যবহার করা কাজে লাগে। Cairo-তে আমরা এমন একটি দলকে স্ট্রাক্ট বলি, আর দলের প্রতিটি আইটেমকে বলি স্ট্রাক্টের একটি ফিল্ড। একটি স্ট্রাক্ট কোন কোন ফিল্ড থাকতে পারে সেই সাধারণ সেটটি ঠিক করে দেয়, কিন্তু স্ট্রাক্টের একটি নির্দিষ্ট উদাহরণকে ইনস্ট্যান্স বলা হয়।
তাছাড়া, স্ট্রাক্টে মেথড ডিফাইন করা যায়, যেগুলোর ফিল্ডগুলোতে অ্যাক্সেস থাকে।
সেক্ষেত্রে স্ট্রাক্টটিকেই self বলা হয়।
যখন একটি মেথড ref self: SomeStruct ব্যবহার করে, তখন ফিল্ডগুলো পরিবর্তন করা যায়, অর্থাৎ মিউটেট করা যায়।
আর যখন একটি মেথড self: SomeStruct বা self: @SomeStruct ব্যবহার করে, তখন ফিল্ডগুলো পরিবর্তন করা যায় না: সেগুলো ইমিউটেবল।
মিউটেবিলিটি নিয়ন্ত্রণ করলে বরো-চেকার নিশ্চিত করতে পারে যে Cairo-তে এক গোটা শ্রেণির কনকারেন্সি bug আর কখনোই ঘটবে না।
এই অনুশীলনীতে আপনি একটি স্ট্রাক্টে দুই ধরনের মেথড ইমপ্লিমেন্ট করবেন। প্রথম ধরনের মেথডগুলোকে সাধারণত গেটার বলা হয়: এগুলো স্ট্রাক্টের ফিল্ডগুলো বাইরের জগতের সামনে তুলে ধরে, কিন্তু অন্য কাউকে সেই মান মিউটেট করতে দেয় না।
আপনি আরেক ধরনের মেথডও ইমপ্লিমেন্ট করবেন, যেগুলোকে সাধারণত সেটার বলা হয়। এগুলো ফিল্ডের মান পরিবর্তন করে। Cairo-তে সেটার খুব একটা কমন নয়। কোনো ফিল্ড যদি অবাধে পরিবর্তন করা যায়, তাহলে সেটিকে শুধু পাবলিক করে দেওয়াই বেশি কমন। তবে ফিল্ড আপডেট করার সময় সাইড এফেক্ট থাকা দরকার হলে সেটার কাজে লাগে।
struct কিওয়ার্ড দিয়ে স্ট্রাক্ট ডিফাইন করা হয়, তারপর থাকে স্ট্রাক্টটি যে টাইপের বর্ণনা দিচ্ছে সেই টাইপের বড় হাতের অক্ষরে লেখা নাম:
struct Item {}
এরপর আরও টাইপকে স্ট্রাক্টের ফিল্ড হিসেবে স্ট্রাক্টের বডিতে আনা হয়, প্রতিটির নিজস্ব টাইপ থাকে:
struct Item {
name: String,
weight: f32,
worth: u32,
}
একটি ট্রেইট মেথডের একটি সেট নির্ধারণ করে, যা কোনো টাইপ ইমপ্লিমেন্ট করতে পারে (আমরা এখানে স্ট্রাক্টেই মন দেব, তবে enum-এর উপরও ট্রেইট ইমপ্লিমেন্ট করা যায়)।
কোনো টাইপ এই ট্রেইট ইমপ্লিমেন্ট করলে সেই টাইপের ইনস্ট্যান্সের উপর এই মেথডগুলো কল করা যায়।
trait কিওয়ার্ড দিয়ে ট্রেইট ডিফাইন করা হয়, আর ট্রেইটের ভেতরে আমরা সেই মেথড সিগনেচার ডিফাইন করি যেগুলো আমাদের টাইপের ইমপ্লিমেন্ট করা দরকার।
trait ImplTrait {
// Define the method signature
fn new() -> Item;
}
সবশেষে, impl ব্লকের ভেতরে স্ট্রাক্টে মেথড ডিফাইন করা যায়, যা ডিফাইন করা ট্রেইটটি ইমপ্লিমেন্ট করে:
impl ItemImpl of ImplTrait {
// initializes and returns a new instance of our Item struct
fn new() -> Item {
Item {}
}
}
আপনি একটি হেলথ-মনিটরিং সিস্টেম তৈরি করার কাজ করছেন। এর অংশ হিসেবে আপনার ব্যবহারকারীদের স্বাস্থ্য পরিসংখ্যান সংরক্ষণ করা প্রয়োজন।
আপনি শুরু করবেন একটি impl ব্লকে থাকা কিছু স্টাব করা ফাংশন আর নিচের স্ট্রাক্ট ডেফিনিশনটি নিয়ে:
pub struct User {
name: String,
age: u32,
weight: u32,
}
আপনার লক্ষ্য হলো impl ব্লকে ডিফাইন করা User struct-এর ওপর স্টাব করা মেথডগুলো ইমপ্লিমেন্ট করা।
উদাহরণস্বরূপ, new মেথডটি নির্দিষ্ট নাম, বয়স ও ওজন মান নিয়ে User স্ট্রাক্টের একটি ইনস্ট্যান্স রিটার্ন করবে।
let mut bob = User::new("Bob", 32, 72);
// Returns: a User with name "Bob", age 32, and weight 72
weight মেথডটি User-এর ওজন রিটার্ন করবে।
bob.weight();
// Returns: 72
set_age মেথডটি User-এর বয়স সেট করবে।
bob.set_age(33);
// Updates Bob's age to 33; happy birthday Bob!
শুভকামনা!
Exercism-এ সাইন আপ করুন, Cairo ট্র্যাকের 25টি কনসেপ্ট68টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।