খণ্ডনযোগ্যতা: একটি প্যাটার্ন ম্যাচ করতে ব্যর্থ হতে পারে কিনা (Refutability: Whether a Pattern Might Fail to Match)
প্যাটার্ন দুটি রূপে আসে: খণ্ডনযোগ্য (refutable) এবং অখণ্ডনযোগ্য (irrefutable)। যে প্যাটার্নগুলো পাস করা যেকোনো সম্ভাব্য মানের জন্য মিলবে, সেগুলো হলো অখণ্ডনযোগ্য (irrefutable)। একটি উদাহরণ হলো let x = 5;
স্টেটমেন্টে x
, কারণ x
যেকোনো কিছুর সাথে মেলে এবং তাই ম্যাচ করতে ব্যর্থ হতে পারে না। যে প্যাটার্নগুলো কিছু সম্ভাব্য মানের জন্য ম্যাচ করতে ব্যর্থ হতে পারে, সেগুলো হলো খণ্ডনযোগ্য (refutable)। একটি উদাহরণ হলো if let Some(x) = a_value
এক্সপ্রেশনে Some(x)
, কারণ যদি a_value
ভেরিয়েবলের মান Some
-এর পরিবর্তে None
হয়, তবে Some(x)
প্যাটার্নটি মিলবে না।
ফাংশন প্যারামিটার, let
স্টেটমেন্ট এবং for
লুপ কেবল অখণ্ডনযোগ্য প্যাটার্ন গ্রহণ করতে পারে, কারণ মানগুলো না মিললে প্রোগ্রামটি অর্থপূর্ণ কিছু করতে পারে না। if let
এবং while let
এক্সপ্রেশন এবং let...else
স্টেটমেন্ট খণ্ডনযোগ্য এবং অখণ্ডনযোগ্য উভয় প্যাটার্ন গ্রহণ করে, কিন্তু কম্পাইলার অখণ্ডনযোগ্য প্যাটার্নের বিরুদ্ধে সতর্ক করে কারণ, সংজ্ঞা অনুসারে, এগুলো সম্ভাব্য ব্যর্থতা পরিচালনা করার জন্য উদ্দিষ্ট: একটি কন্ডিশনালের কার্যকারিতা তার সফলতা বা ব্যর্থতার উপর নির্ভর করে ভিন্নভাবে কাজ করার ক্ষমতার মধ্যে নিহিত।
সাধারণত, আপনাকে খণ্ডনযোগ্য এবং অখণ্ডনযোগ্য প্যাটার্নের মধ্যে পার্থক্য নিয়ে চিন্তা করতে হবে না; তবে, খণ্ডনযোগ্যতার ধারণাটির সাথে আপনার পরিচিত থাকা প্রয়োজন যাতে আপনি যখন কোনো এরর মেসেজে এটি দেখেন তখন প্রতিক্রিয়া জানাতে পারেন। সেইসব ক্ষেত্রে, কোডের উদ্দিষ্ট আচরণের উপর নির্ভর করে আপনাকে হয় প্যাটার্ন বা আপনি যে কনস্ট্রাক্টটি প্যাটার্নের সাথে ব্যবহার করছেন তা পরিবর্তন করতে হবে।
চলুন একটি উদাহরণ দেখি যখন আমরা একটি খণ্ডনযোগ্য প্যাটার্ন এমন জায়গায় ব্যবহার করার চেষ্টা করি যেখানে রাস্ট একটি অখণ্ডনযোগ্য প্যাটার্ন চায় এবং এর বিপরীতটি। লিস্টিং ১৯-৮ একটি let
স্টেটমেন্ট দেখায়, কিন্তু প্যাটার্নের জন্য, আমরা Some(x)
নির্দিষ্ট করেছি, যা একটি খণ্ডনযোগ্য প্যাটার্ন। যেমনটি আপনি আশা করতে পারেন, এই কোডটি কম্পাইল হবে না।
fn main() {
let some_option_value: Option<i32> = None;
let Some(x) = some_option_value;
}```
</Listing>
যদি `some_option_value` একটি `None` মান হতো, তবে এটি `Some(x)` প্যাটার্নের সাথে ম্যাচ করতে ব্যর্থ হতো, যার মানে প্যাটার্নটি খণ্ডনযোগ্য। তবে, `let` স্টেটমেন্ট কেবল একটি অখণ্ডনযোগ্য প্যাটার্ন গ্রহণ করতে পারে কারণ কোডের একটি `None` মান নিয়ে করার মতো বৈধ কিছু নেই। কম্পাইল টাইমে, রাস্ট অভিযোগ করবে যে আমরা একটি খণ্ডনযোগ্য প্যাটার্ন ব্যবহার করার চেষ্টা করেছি যেখানে একটি অখণ্ডনযোগ্য প্যাটার্ন প্রয়োজন:
```console
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0005]: refutable pattern in local binding
--> src/main.rs:3:9
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
= note: the matched value is of type `Option<i32>`
help: you might want to use `let else` to handle the variant that isn't matched
|
3 | let Some(x) = some_option_value else { todo!() };
| ++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
যেহেতু আমরা Some(x)
প্যাটার্ন দিয়ে প্রতিটি বৈধ মান কভার করিনি (এবং করতে পারতাম না!), তাই রাস্ট সঠিকভাবে একটি কম্পাইলার এরর তৈরি করে।
যদি আমাদের এমন একটি খণ্ডনযোগ্য প্যাটার্ন থাকে যেখানে একটি অখণ্ডনযোগ্য প্যাটার্ন প্রয়োজন, আমরা প্যাটার্ন ব্যবহারকারী কোড পরিবর্তন করে এটি ঠিক করতে পারি: let
ব্যবহার করার পরিবর্তে, আমরা let else
ব্যবহার করতে পারি। তারপর, যদি প্যাটার্নটি না মেলে, কোডটি কেবল কোঁকড়া বন্ধনীর (curly brackets) ভেতরের কোডটি এড়িয়ে যাবে, যা এটিকে বৈধভাবে চালিয়ে যাওয়ার একটি উপায় দেয়। লিস্টিং ১৯-৯ দেখায় কীভাবে লিস্টিং ১৯-৮-এর কোডটি ঠিক করতে হয়।
fn main() { let some_option_value: Option<i32> = None; let Some(x) = some_option_value else { return; }; }
আমরা কোডটিকে একটি মুক্তির পথ দিয়েছি! এই কোডটি সম্পূর্ণ বৈধ, যদিও এর মানে হলো আমরা একটি সতর্কতা না পেয়ে একটি অখণ্ডনযোগ্য প্যাটার্ন ব্যবহার করতে পারি না। যদি আমরা let...else
-কে এমন একটি প্যাটার্ন দিই যা সর্বদা মিলবে, যেমন x
, যেমনটি লিস্টিং ১৯-১০-এ দেখানো হয়েছে, কম্পাইলার একটি সতর্কতা দেবে।
fn main() { let x = 5 else { return; }; }``` </Listing> রাস্ট অভিযোগ করে যে একটি অখণ্ডনযোগ্য প্যাটার্নের সাথে `let...else` ব্যবহার করা অর্থহীন: ```console $ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) warning: irrefutable `let...else` pattern --> src/main.rs:2:5 | 2 | let x = 5 else { | ^^^^^^^^^ | = note: this pattern will always match, so the `else` clause is useless = help: consider removing the `else` clause = note: `#[warn(irrefutable_let_patterns)]` on by default warning: `patterns` (bin "patterns") generated 1 warning Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s Running `target/debug/patterns`
এই কারণে, ম্যাচ arm-গুলোকে অবশ্যই খণ্ডনযোগ্য প্যাটার্ন ব্যবহার করতে হবে, শেষ arm ব্যতীত, যা যেকোনো অবশিষ্ট মানকে একটি অখণ্ডনযোগ্য প্যাটার্ন দিয়ে ম্যাচ করা উচিত। রাস্ট আমাদের কেবল একটি arm সহ একটি match
-এ একটি অখণ্ডনযোগ্য প্যাটার্ন ব্যবহার করার অনুমতি দেয়, কিন্তু এই সিনট্যাক্সটি বিশেষভাবে কার্যকর নয় এবং একটি সহজ let
স্টেটমেন্ট দ্বারা প্রতিস্থাপিত হতে পারে।
এখন আপনি জানেন কোথায় প্যাটার্ন ব্যবহার করতে হয় এবং খণ্ডনযোগ্য ও অখণ্ডনযোগ্য প্যাটার্নের মধ্যে পার্থক্য কী, চলুন আমরা প্যাটার্ন তৈরি করার জন্য যে সমস্ত সিনট্যাক্স ব্যবহার করতে পারি তা কভার করি।