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

ডেটা টাইপ

রাস্ট-এর প্রতিটি ভ্যালুর একটি নির্দিষ্ট ডেটা টাইপ থাকে, যা রাস্টকে বলে দেয় কী ধরনের ডেটা নির্দিষ্ট করা হচ্ছে যাতে এটি সেই ডেটার সাথে কীভাবে কাজ করতে হবে তা জানতে পারে। আমরা দুটি ডেটা টাইপের উপসেট দেখব: স্কেলার (scalar) এবং কম্পাউন্ড (compound)।

মনে রাখবেন যে রাস্ট একটি স্ট্যাটিক্যালি টাইপড ল্যাঙ্গুয়েজ, যার মানে হল কম্পাইল করার সময় এটিকে অবশ্যই সমস্ত ভ্যারিয়েবলের টাইপ জানতে হবে। কম্পাইলার সাধারণত আমরা কোন টাইপ ব্যবহার করতে চাই তা ভ্যালু এবং আমরা কীভাবে এটি ব্যবহার করি তার উপর ভিত্তি করে অনুমান করতে পারে। যখন অনেকগুলো টাইপ সম্ভব হয়, যেমন অধ্যায় ২-এর "অনুমানের সাথে গোপন সংখ্যার তুলনা" বিভাগে আমরা যখন parse ব্যবহার করে একটি String-কে একটি নিউমেরিক টাইপে রূপান্তর করেছিলাম, তখন আমাদের অবশ্যই একটি টাইপ অ্যানোটেশন যোগ করতে হবে, যেমন:

#![allow(unused)]
fn main() {
let guess: u32 = "42".parse().expect("Not a number!");
}

যদি আমরা উপরের কোডে দেখানো : u32 টাইপ অ্যানোটেশন যোগ না করি, রাস্ট নিম্নলিখিত এররটি প্রদর্শন করবে, যার মানে হল আমরা কোন টাইপ ব্যবহার করতে চাই তা জানার জন্য কম্পাইলারের আমাদের কাছ থেকে আরও তথ্য প্রয়োজন:

$ cargo build
   Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations)
error[E0284]: type annotations needed
 --> src/main.rs:2:9
  |
2 |     let guess = "42".parse().expect("Not a number!");
  |         ^^^^^        ----- type must be known at this point
  |
  = note: cannot satisfy `<_ as FromStr>::Err == _`
help: consider giving `guess` an explicit type
  |
2 |     let guess: /* Type */ = "42".parse().expect("Not a number!");
  |              ++++++++++++

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

আপনি অন্যান্য ডেটা টাইপের জন্য বিভিন্ন টাইপ অ্যানোটেশন দেখতে পাবেন।

স্কেলার টাইপ (Scalar Types)

একটি স্কেলার টাইপ একটি একক মান উপস্থাপন করে। রাস্টের চারটি প্রাথমিক স্কেলার টাইপ রয়েছে: ইন্টিজার (integers), ফ্লোটিং-পয়েন্ট নাম্বার (floating-point numbers), বুলিয়ান (Booleans) এবং ক্যারেক্টার (characters)। আপনি হয়তো অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজ থেকে এগুলোর সাথে পরিচিত। চলুন রাস্ট-এ এগুলো কীভাবে কাজ করে তা দেখা যাক।

ইন্টিজার টাইপ (Integer Types)

একটি ইন্টিজার হল একটি সংখ্যা যার কোনো ভগ্নাংশ নেই। আমরা অধ্যায় ২-এ একটি ইন্টিজার টাইপ, u32 টাইপ ব্যবহার করেছি। এই টাইপ ডিক্লারেশনটি নির্দেশ করে যে এর সাথে যুক্ত ভ্যালুটি একটি আনসাইন্ড ইন্টিজার (সাইনড ইন্টিজার টাইপগুলো u এর পরিবর্তে i দিয়ে শুরু হয়) যা ৩২ বিট জায়গা নেয়। সারণী ৩-১ রাস্টের বিল্ট-ইন ইন্টিজার টাইপগুলো দেখায়। আমরা একটি ইন্টিজার ভ্যালুর টাইপ ঘোষণা করতে এই ভ্যারিয়েন্টগুলোর যেকোনো একটি ব্যবহার করতে পারি।

সারণী ৩-১: রাস্ট-এ ইন্টিজার টাইপ

দৈর্ঘ্য (Length)সাইনড (Signed)আনসাইনড (Unsigned)
৮-বিটi8u8
১৬-বিটi16u16
৩২-বিটi32u32
৬৪-বিটi64u64
১২৮-বিটi128u128
আর্কিটেকচার নির্ভরisizeusize

প্রতিটি ভ্যারিয়েন্ট সাইনড বা আনসাইনড হতে পারে এবং এর একটি সুস্পষ্ট আকার রয়েছে। সাইনড এবং আনসাইনড বলতে বোঝায় যে সংখ্যাটি ঋণাত্মক হওয়া সম্ভব কিনা—অন্য কথায়, সংখ্যাটির সাথে একটি চিহ্ন (সাইন) থাকার প্রয়োজন আছে কিনা (সাইনড) অথবা এটি কেবল ধনাত্মক হবে এবং তাই কোনো চিহ্ন ছাড়াই উপস্থাপন করা যেতে পারে (আনসাইনড)। এটা কাগজে সংখ্যা লেখার মতো: যখন চিহ্ন গুরুত্বপূর্ণ, তখন একটি সংখ্যা প্লাস বা মাইনাস চিহ্ন দিয়ে দেখানো হয়; তবে, যখন সংখ্যাটি ধনাত্মক বলে ধরে নেওয়া নিরাপদ, তখন এটি কোনো চিহ্ন ছাড়াই দেখানো হয়। সাইনড সংখ্যা two’s complement রিপ্রেজেন্টেশন ব্যবহার করে সংরক্ষণ করা হয়।

প্রতিটি সাইনড ভ্যারিয়েন্ট −(২n − ১) থেকে ২n − ১ − ১ পর্যন্ত সংখ্যা সংরক্ষণ করতে পারে, যেখানে n হল সেই ভ্যারিয়েন্টটি যে বিট সংখ্যা ব্যবহার করে। তাই একটি i8 −(২) থেকে ২ − ১ পর্যন্ত, যা −১২৮ থেকে ১২৭ এর সমান, সংখ্যা সংরক্ষণ করতে পারে। আনসাইনড ভ্যারিয়েন্টগুলো ০ থেকে ২n − ১ পর্যন্ত সংখ্যা সংরক্ষণ করতে পারে, তাই একটি u8 ০ থেকে ২ − ১ পর্যন্ত, যা ০ থেকে ২৫৫ এর সমান, সংখ্যা সংরক্ষণ করতে পারে।

এছাড়াও, isize এবং usize টাইপগুলো আপনার প্রোগ্রাম যে কম্পিউটারের আর্কিটেকচারে চলছে তার উপর নির্ভর করে: ৬৪-বিট আর্কিটেকচারে থাকলে ৬৪ বিট এবং ৩২-বিট আর্কিটেকচারে থাকলে ৩২ বিট।

আপনি সারণী ৩-২-এ দেখানো যেকোনো ফর্মে ইন্টিজার লিটারেল লিখতে পারেন। মনে রাখবেন যে যেসব নাম্বার লিটারেল একাধিক নিউমেরিক টাইপ হতে পারে, সেগুলোতে টাইপ নির্দিষ্ট করার জন্য একটি টাইপ সাফিক্স, যেমন 57u8, অনুমোদিত। নাম্বার লিটারেলগুলোতে সংখ্যাটি সহজে পড়ার জন্য একটি ভিজ্যুয়াল সেপারেটর হিসাবে _ ব্যবহার করা যেতে পারে, যেমন 1_000, যার মান 1000 নির্দিষ্ট করার মতোই হবে।

সারণী ৩-২: রাস্ট-এ ইন্টিজার লিটারেল

নাম্বার লিটারেলউদাহরণ
ডেসিমেল98_222
হেক্স0xff
অক্টাল0o77
বাইনারি0b1111_0000
বাইট (u8 কেবল)b'A'

তাহলে আপনি কীভাবে জানবেন কোন ধরনের ইন্টিজার ব্যবহার করবেন? আপনি যদি অনিশ্চিত হন, রাস্টের ডিফল্টগুলো সাধারণত শুরু করার জন্য ভাল জায়গা: ইন্টিজার টাইপগুলো ডিফল্টভাবে i32 হয়। isize বা usize ব্যবহার করার প্রাথমিক পরিস্থিতি হল কোনো ধরনের কালেকশন ইনডেক্স করার সময়।

ইন্টিজার ওভারফ্লো (Integer Overflow)

ধরা যাক আপনার কাছে u8 টাইপের একটি ভ্যারিয়েবল আছে যা ০ থেকে ২৫৫ এর মধ্যে মান ধারণ করতে পারে। আপনি যদি ভ্যারিয়েবলটিকে সেই পরিসরের বাইরের কোনো মানে পরিবর্তন করার চেষ্টা করেন, যেমন ২৫৬, তাহলে ইন্টিজার ওভারফ্লো ঘটবে, যা দুটি আচরণের একটির কারণ হতে পারে। আপনি যখন ডিবাগ মোডে কম্পাইল করছেন, তখন রাস্ট ইন্টিজার ওভারফ্লোর জন্য চেক অন্তর্ভুক্ত করে যা এই আচরণ ঘটলে আপনার প্রোগ্রামকে রানটাইমে প্যানিক (panic) করায়। রাস্ট প্যানিকিং শব্দটি ব্যবহার করে যখন একটি প্রোগ্রাম একটি এরর সহ বন্ধ হয়ে যায়; আমরা অধ্যায় ৯-এর "Unrecoverable Errors with panic!" বিভাগে প্যানিক নিয়ে আরও गहराई से আলোচনা করব।

আপনি যখন --release ফ্ল্যাগ দিয়ে রিলিজ মোডে কম্পাইল করছেন, তখন রাস্ট প্যানিক সৃষ্টিকারী ইন্টিজার ওভারফ্লোর জন্য চেক অন্তর্ভুক্ত করে না। পরিবর্তে, যদি ওভারফ্লো ঘটে, রাস্ট টু'স কমপ্লিমেন্ট র‍্যাপিং (two’s complement wrapping) করে। সংক্ষেপে, টাইপটি যে সর্বোচ্চ মান ধারণ করতে পারে তার চেয়ে বড় মানগুলো "র‍্যাপ অ্যারাউন্ড" করে টাইপটি যে সর্বনিম্ন মান ধারণ করতে পারে সেখানে চলে আসে। একটি u8-এর ক্ষেত্রে, মান ২৫৬ হয়ে যায় ০, মান ২৫৭ হয়ে যায় ১, এবং এভাবেই চলতে থাকে। প্রোগ্রামটি প্যানিক করবে না, কিন্তু ভ্যারিয়েবলটির একটি এমন মান থাকবে যা সম্ভবত আপনি যা আশা করেছিলেন তা নয়। ইন্টিজার ওভারফ্লোর র‍্যাপিং আচরণের উপর নির্ভর করা একটি এরর হিসাবে বিবেচিত হয়।

ওভারফ্লোর সম্ভাবনা স্পষ্টভাবে পরিচালনা করার জন্য, আপনি প্রিমিটিভ নিউমেরিক টাইপগুলোর জন্য স্ট্যান্ডার্ড লাইব্রেরি দ্বারা প্রদত্ত এই মেথডগুলোর পরিবার ব্যবহার করতে পারেন:

  • wrapping_* মেথড, যেমন wrapping_add, দিয়ে সমস্ত মোডে র‍্যাপ করুন।
  • checked_* মেথড দিয়ে ওভারফ্লো হলে None মান প্রদান করুন।
  • overflowing_* মেথড দিয়ে মান এবং একটি বুলিয়ান যা নির্দেশ করে ওভারফ্লো হয়েছে কিনা তা প্রদান করুন।
  • saturating_* মেথড দিয়ে মানের সর্বনিম্ন বা সর্বোচ্চ মানে স্যাচুরেট করুন।

ফ্লোটিং-পয়েন্ট টাইপ (Floating-Point Types)

রাস্ট-এ ফ্লোটিং-পয়েন্ট নাম্বার, যা দশমিক বিন্দুযুক্ত সংখ্যা, এর জন্য দুটি প্রিমিটিভ টাইপও রয়েছে। রাস্টের ফ্লোটিং-পয়েন্ট টাইপগুলো হল f32 এবং f64, যা যথাক্রমে ৩২ বিট এবং ৬৪ বিট আকারের। ডিফল্ট টাইপ হল f64 কারণ আধুনিক সিপিইউগুলিতে, এটি f32-এর মতো প্রায় একই গতির কিন্তু আরও বেশি নির্ভুলতা (precision) দিতে সক্ষম। সমস্ত ফ্লোটিং-পয়েন্ট টাইপ সাইনড।

এখানে একটি উদাহরণ যা ফ্লোটিং-পয়েন্ট নাম্বারগুলোকে কার্যকর অবস্থায় দেখায়:

ফাইলের নাম: src/main.rs

fn main() {
    let x = 2.0; // f64

    let y: f32 = 3.0; // f32
}

ফ্লোটিং-পয়েন্ট নাম্বারগুলো IEEE-754 স্ট্যান্ডার্ড অনুযায়ী উপস্থাপিত হয়।

নিউমেরিক অপারেশনস (Numeric Operations)

রাস্ট সমস্ত নাম্বার টাইপের জন্য আপনার প্রত্যাশিত মৌলিক গাণিতিক অপারেশনগুলো সমর্থন করে: যোগ, বিয়োগ, গুণ, ভাগ এবং ভাগশেষ (remainder)। ইন্টিজার ডিভিশন নিকটতম পূর্ণসংখ্যার দিকে শূন্যের দিকে ছেঁটে (truncates) ফেলে। নিম্নলিখিত কোডটি দেখায় যে আপনি কীভাবে একটি let স্টেটমেন্টে প্রতিটি নিউমেরিক অপারেশন ব্যবহার করবেন:

ফাইলের নাম: src/main.rs

fn main() {
    // addition
    let sum = 5 + 10;

    // subtraction
    let difference = 95.5 - 4.3;

    // multiplication
    let product = 4 * 30;

    // division
    let quotient = 56.7 / 32.2;
    let truncated = -5 / 3; // Results in -1

    // remainder
    let remainder = 43 % 5;
}

এই স্টেটমেন্টগুলোর প্রতিটি এক্সপ্রেশন একটি গাণিতিক অপারেটর ব্যবহার করে এবং একটি একক মানে মূল্যায়ন করে, যা তারপর একটি ভ্যারিয়েবলের সাথে বাইন্ড করা হয়। পরিশিষ্ট বি তে রাস্ট দ্বারা প্রদত্ত সমস্ত অপারেটরের একটি তালিকা রয়েছে।

বুলিয়ান টাইপ (The Boolean Type)

অন্যান্য বেশিরভাগ প্রোগ্রামিং ল্যাঙ্গুয়েজের মতোই, রাস্ট-এ একটি বুলিয়ান টাইপের দুটি সম্ভাব্য মান রয়েছে: true এবং false। বুলিয়ানগুলো এক বাইট আকারের। রাস্ট-এ বুলিয়ান টাইপ bool ব্যবহার করে নির্দিষ্ট করা হয়। উদাহরণস্বরূপ:

ফাইলের নাম: src/main.rs

fn main() {
    let t = true;

    let f: bool = false; // with explicit type annotation
}

বুলিয়ান মান ব্যবহার করার প্রধান উপায় হল কন্ডিশনাল, যেমন একটি if এক্সপ্রেশন। আমরা "কন্ট্রোল ফ্লো" বিভাগে রাস্ট-এ if এক্সপ্রেশন কীভাবে কাজ করে তা কভার করব।

ক্যারেক্টার টাইপ (The Character Type)

রাস্টের char টাইপ হল ভাষার সবচেয়ে আদিম বর্ণানুক্রমিক টাইপ। এখানে char মান ঘোষণা করার কিছু উদাহরণ দেওয়া হল:

ফাইলের নাম: src/main.rs

fn main() {
    let c = 'z';
    let z: char = 'ℤ'; // with explicit type annotation
    let heart_eyed_cat = '😻';
}

লক্ষ্য করুন যে আমরা char লিটারেলগুলোকে একক উদ্ধৃতি (single quotes) দিয়ে নির্দিষ্ট করি, স্ট্রিং লিটারেলের বিপরীতে, যা দ্বৈত উদ্ধৃতি (double quotes) ব্যবহার করে। রাস্টের char টাইপ চার বাইট আকারের এবং একটি ইউনিকোড স্কেলার মান (Unicode Scalar Value) উপস্থাপন করে, যার মানে এটি শুধু ASCII-এর চেয়ে অনেক বেশি কিছু উপস্থাপন করতে পারে। অ্যাকসেন্টেড অক্ষর; চীনা, জাপানি এবং কোরিয়ান অক্ষর; ইমোজি; এবং শূন্য-প্রস্থের স্পেস সবই রাস্ট-এ বৈধ char মান। ইউনিকোড স্কেলার মান U+0000 থেকে U+D7FF এবং U+E000 থেকে U+10FFFF পর্যন্ত অন্তর্ভুক্ত। তবে, ইউনিকোডে "ক্যারেক্টার" realmente একটি ধারণা নয়, তাই "ক্যারেক্টার" বলতে আপনার মানবিক অনুভূতি রাস্ট-এ একটি char যা তার সাথে নাও মিলতে পারে। আমরা এই বিষয়টি অধ্যায় ৮-এর "Storing UTF-8 Encoded Text with Strings" বিভাগে বিস্তারিতভাবে আলোচনা করব।

কম্পাউন্ড টাইপ (Compound Types)

কম্পাউন্ড টাইপ একাধিক মানকে একটি টাইপে গ্রুপ করতে পারে। রাস্টের দুটি প্রিমিটিভ কম্পাউন্ড টাইপ রয়েছে: টাপল (tuples) এবং অ্যারে (arrays)।

টাপল টাইপ (The Tuple Type)

একটি টাপল হল বিভিন্ন টাইপের একাধিক মানকে একটি কম্পাউন্ড টাইপে একত্রিত করার একটি সাধারণ উপায়। টাপলগুলোর একটি নির্দিষ্ট দৈর্ঘ্য থাকে: একবার ঘোষণা করা হলে, তারা আকারে বাড়তে বা কমতে পারে না।

আমরা প্রথম বন্ধনীর ভিতরে কমা দ্বারা পৃথক করা মানের একটি তালিকা লিখে একটি টাপল তৈরি করি। টাপলের প্রতিটি অবস্থানের একটি টাইপ থাকে, এবং টাপলের বিভিন্ন মানের টাইপ একই হতে হবে এমন কোনো কথা নেই। আমরা এই উদাহরণে ঐচ্ছিক টাইপ অ্যানোটেশন যোগ করেছি:

ফাইলের নাম: src/main.rs

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}

tup ভ্যারিয়েবলটি পুরো টাপলের সাথে বাইন্ড করে কারণ একটি টাপলকে একটি একক কম্পাউন্ড উপাদান হিসাবে বিবেচনা করা হয়। একটি টাপল থেকে পৃথক মানগুলো পেতে, আমরা প্যাটার্ন ম্যাচিং ব্যবহার করে একটি টাপল মানকে ডিস্ট্রাকচার (destructure) করতে পারি, এভাবে:

ফাইলের নাম: src/main.rs

fn main() {
    let tup = (500, 6.4, 1);

    let (x, y, z) = tup;

    println!("The value of y is: {y}");
}

এই প্রোগ্রামটি প্রথমে একটি টাপল তৈরি করে এবং এটিকে tup ভ্যারিয়েবলের সাথে বাইন্ড করে। তারপরে এটি let এর সাথে একটি প্যাটার্ন ব্যবহার করে tup কে নিয়ে তিনটি পৃথক ভ্যারিয়েবল, x, y, এবং z তে পরিণত করে। একে ডিস্ট্রাকচারিং বলা হয় কারণ এটি একক টাপলকে তিনটি অংশে ভেঙে দেয়। অবশেষে, প্রোগ্রামটি y-এর মান প্রিন্ট করে, যা 6.4

আমরা একটি পিরিয়ড (.) এবং তারপরে আমরা যে মানটি অ্যাক্সেস করতে চাই তার ইনডেক্স ব্যবহার করে সরাসরি একটি টাপল উপাদান অ্যাক্সেস করতে পারি। উদাহরণস্বরূপ:

ফাইলের নাম: src/main.rs

fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);

    let five_hundred = x.0;

    let six_point_four = x.1;

    let one = x.2;
}

এই প্রোগ্রামটি x টাপল তৈরি করে এবং তারপরে তাদের নিজ নিজ ইনডেক্স ব্যবহার করে টাপলের প্রতিটি উপাদান অ্যাক্সেস করে। বেশিরভাগ প্রোগ্রামিং ল্যাঙ্গুয়েজের মতোই, একটি টাপলের প্রথম ইনডেক্স হল ০।

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

অ্যারে টাইপ (The Array Type)

একাধিক মানের একটি সংগ্রহ থাকার আরেকটি উপায় হল একটি অ্যারে। একটি টাপলের বিপরীতে, একটি অ্যারের প্রতিটি উপাদানের একই টাইপ থাকতে হবে। অন্য কিছু ভাষার অ্যারের বিপরীতে, রাস্ট-এ অ্যারেগুলোর একটি নির্দিষ্ট দৈর্ঘ্য থাকে।

আমরা একটি অ্যারের মানগুলো বর্গাকার বন্ধনীর ভিতরে কমা দ্বারা পৃথক করা তালিকা হিসাবে লিখি:

ফাইলের নাম: src/main.rs

fn main() {
    let a = [1, 2, 3, 4, 5];
}

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

তবে, অ্যারেগুলো আরও বেশি দরকারী যখন আপনি জানেন যে উপাদানের সংখ্যা পরিবর্তন করার প্রয়োজন হবে না। উদাহরণস্বরূপ, আপনি যদি একটি প্রোগ্রামে মাসের নাম ব্যবহার করেন, তবে আপনি সম্ভবত একটি ভেক্টরর পরিবর্তে একটি অ্যারে ব্যবহার করবেন কারণ আপনি জানেন যে এটিতে সর্বদা ১২টি উপাদান থাকবে:

#![allow(unused)]
fn main() {
let months = ["January", "February", "March", "April", "May", "June", "July",
              "August", "September", "October", "November", "December"];
}

আপনি একটি অ্যারের টাইপ বর্গাকার বন্ধনী ব্যবহার করে প্রতিটি উপাদানের টাইপ, একটি সেমিকোলন এবং তারপরে অ্যারের উপাদানের সংখ্যা দিয়ে লিখেন, এভাবে:

#![allow(unused)]
fn main() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
}

এখানে, i32 প্রতিটি উপাদানের টাইপ। সেমিকোলনের পরে, 5 সংখ্যাটি নির্দেশ করে যে অ্যারেটিতে পাঁচটি উপাদান রয়েছে।

আপনি প্রতিটি উপাদানের জন্য একই মান ধারণ করার জন্য একটি অ্যারে ইনিশিয়ালাইজ করতে পারেন, প্রাথমিক মান নির্দিষ্ট করে, তারপর একটি সেমিকোলন, এবং তারপর বর্গাকার বন্ধনীতে অ্যারের দৈর্ঘ্য, যেমনটি এখানে দেখানো হয়েছে:

#![allow(unused)]
fn main() {
let a = [3; 5];
}

a নামের অ্যারেটিতে 5 টি উপাদান থাকবে যা সব প্রাথমিকভাবে 3 মানে সেট করা হবে। এটি let a = [3, 3, 3, 3, 3]; লেখার মতোই কিন্তু আরও সংক্ষিপ্ত উপায়ে।

অ্যারে উপাদান অ্যাক্সেস করা

একটি অ্যারে হল একটি পরিচিত, নির্দিষ্ট আকারের মেমরির একক খণ্ড যা স্ট্যাকে বরাদ্দ করা যেতে পারে। আপনি ইনডেক্সিং ব্যবহার করে একটি অ্যারের উপাদান অ্যাক্সেস করতে পারেন, এভাবে:

ফাইলের নাম: src/main.rs

fn main() {
    let a = [1, 2, 3, 4, 5];

    let first = a[0];
    let second = a[1];
}

এই উদাহরণে, first নামের ভ্যারিয়েবলটি 1 মান পাবে কারণ এটি অ্যারের [0] ইনডেক্সে থাকা মান। second নামের ভ্যারিয়েবলটি অ্যারের [1] ইনডেক্স থেকে 2 মান পাবে।

অবৈধ অ্যারে উপাদান অ্যাক্সেস

চলুন দেখি আপনি যদি একটি অ্যারের শেষ প্রান্তের বাইরের কোনো উপাদান অ্যাক্সেস করার চেষ্টা করেন তবে কী ঘটে। ধরা যাক আপনি অধ্যায় ২-এর অনুমান করার গেমের মতো এই কোডটি চালান, ব্যবহারকারীর কাছ থেকে একটি অ্যারে ইনডেক্স পেতে:

ফাইলের নাম: src/main.rs

use std::io;

fn main() {
    let a = [1, 2, 3, 4, 5];

    println!("Please enter an array index.");

    let mut index = String::new();

    io::stdin()
        .read_line(&mut index)
        .expect("Failed to read line");

    let index: usize = index
        .trim()
        .parse()
        .expect("Index entered was not a number");

    let element = a[index];

    println!("The value of the element at index {index} is: {element}");
}

এই কোডটি সফলভাবে কম্পাইল হয়। আপনি যদি cargo run ব্যবহার করে এই কোডটি চালান এবং 0, 1, 2, 3, বা 4 প্রবেশ করান, প্রোগ্রামটি অ্যারের সেই ইনডেক্সে থাকা সংশ্লিষ্ট মানটি প্রিন্ট করবে। আপনি যদি পরিবর্তে অ্যারের শেষের বাইরের কোনো সংখ্যা প্রবেশ করান, যেমন 10, আপনি এই ধরনের আউটপুট দেখতে পাবেন:

thread 'main' panicked at src/main.rs:19:19:
index out of bounds: the len is 5 but the index is 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

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

এটি রাস্টের মেমরি সেফটি নীতির একটি উদাহরণ। অনেক নিম্ন-স্তরের ভাষায়, এই ধরনের পরীক্ষা করা হয় না, এবং যখন আপনি একটি ভুল ইনডেক্স প্রদান করেন, তখন অবৈধ মেমরি অ্যাক্সেস করা হতে পারে। রাস্ট আপনাকে এই ধরনের ত্রুটির বিরুদ্ধে সুরক্ষা দেয়, মেমরি অ্যাক্সেসের অনুমতি দিয়ে এবং চালিয়ে যাওয়ার পরিবর্তে অবিলম্বে প্রস্থান করে। অধ্যায় ৯ রাস্টের এরর হ্যান্ডলিং সম্পর্কে আরও আলোচনা করে এবং কীভাবে আপনি পঠনযোগ্য, নিরাপদ কোড লিখতে পারেন যা প্যানিকও করে না বা অবৈধ মেমরি অ্যাক্সেসের অনুমতিও দেয় না।