প্যাটার্ন ম্যাচিং ফাংশনাল প্রোগ্রামিংয়ের একটি শক্তিশালী কনসেপ্ট, যা স্কালায় অত্যন্ত সহজ এবং শক্তিশালীভাবে ইমপ্লিমেন্ট করা হয়েছে। এটি switch বা if-else স্টেটমেন্টের তুলনায় অনেক বেশি নমনীয় এবং কার্যকর। স্কালায় প্যাটার্ন ম্যাচিং ডাটা টাইপ অনুযায়ী কার্যক্রম নির্ধারণ করে এবং খুবই পঠনযোগ্য এবং পরিষ্কার কোড তৈরি করতে সহায়তা করে।
স্কালার প্যাটার্ন ম্যাচিং সাধারণত match কিওয়ার্ড ব্যবহার করে করা হয়, এবং এটি case স্টেটমেন্টের মাধ্যমে বিভিন্ন শর্ত পরীক্ষা করে। এটি শুধু ভ্যালু ম্যাচিং নয়, স্কালার ডাটা স্ট্রাকচারের উপরও কাজ করে, যেমন লিস্ট, এনাম, ক্লাস ইত্যাদি।
১. বেসিক প্যাটার্ন ম্যাচিং
স্কালায় match কিওয়ার্ড ব্যবহার করে একটি নির্দিষ্ট মান বা অভ্যন্তরীণ কাঠামোর সাথে মিলিয়ে একাধিক case ব্লক চেক করা হয়।
উদাহরণ:
object PatternMatchingExample {
def matchNumber(x: Int): String = x match {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case _ => "Unknown"
}
def main(args: Array[String]): Unit = {
println(matchNumber(2)) // Output: Two
println(matchNumber(5)) // Output: Unknown
}
}এখানে:
matchকিওয়ার্ড দ্বারা বিভিন্ন কেস চেক করা হচ্ছে।case _হল ডিফল্ট কেস, যা কোনো মেলানো মান না পেলে চালানো হয়।
২. প্যাটার্ন ম্যাচিং উইথ ডাটা টাইপ
স্কালায় প্যাটার্ন ম্যাচিং ডাটা টাইপের উপরও কাজ করে। আপনি নির্দিষ্ট টাইপের জন্য প্যাটার্ন ম্যাচিং কন্ডিশন তৈরি করতে পারেন।
উদাহরণ:
object PatternMatchingDataType {
def describeType(x: Any): String = x match {
case i: Int => s"Integer: $i"
case s: String => s"String: $s"
case d: Double => s"Double: $d"
case _ => "Unknown Type"
}
def main(args: Array[String]): Unit = {
println(describeType(10)) // Output: Integer: 10
println(describeType("Scala")) // Output: String: Scala
println(describeType(3.14)) // Output: Double: 3.14
println(describeType(true)) // Output: Unknown Type
}
}এখানে:
matchব্লকে প্রতিটিcaseনির্দিষ্ট টাইপের সাথে মিলিয়ে কাজ করছে। যেমন,Int,String,Doubleটাইপের জন্য আলাদা কেস।
৩. প্যাটার্ন ম্যাচিং উইথ লিস্ট
স্কালা প্যাটার্ন ম্যাচিংকে লিস্টের সাথে কাজ করতে ব্যবহার করা হয়, যেখানে আপনি লিস্টের উপাদানগুলোর অবস্থান বা সংখ্যা অনুসারে কেস তৈরি করতে পারেন।
উদাহরণ:
object PatternMatchingList {
def describeList(list: List[Int]): String = list match {
case Nil => "Empty List"
case x :: Nil => s"List with one element: $x"
case x :: y :: Nil => s"List with two elements: $x, $y"
case x :: xs => s"List with more than two elements, first element is $x"
}
def main(args: Array[String]): Unit = {
println(describeList(List())) // Output: Empty List
println(describeList(List(1))) // Output: List with one element: 1
println(describeList(List(1, 2))) // Output: List with two elements: 1, 2
println(describeList(List(1, 2, 3))) // Output: List with more than two elements, first element is 1
}
}এখানে:
::লিস্টের প্রথম উপাদানকে চিহ্নিত করে এবং বাকি উপাদানগুলিকে সাবলীলভাবে অ্যাক্সেস করতে সাহায্য করে।Nilএকটি খালি লিস্টের জন্য ব্যবহৃত হয়।
৪. অপশন এবং প্যাটার্ন ম্যাচিং
স্কালার Option টাইপের সাথে প্যাটার্ন ম্যাচিং ব্যবহার করা অনেক জনপ্রিয়, কারণ এটি মানের উপস্থিতি বা অনুপস্থিতি চেক করতে সহায়তা করে। Some এবং None হল অপশনের দুটি অবস্থা।
উদাহরণ:
object PatternMatchingOption {
def processOption(opt: Option[Int]): String = opt match {
case Some(value) => s"Found value: $value"
case None => "No value found"
}
def main(args: Array[String]): Unit = {
println(processOption(Some(10))) // Output: Found value: 10
println(processOption(None)) // Output: No value found
}
}এখানে:
Someব্যবহার করে মান দেওয়া হয়েছে এবংNoneমানের অনুপস্থিতি চিহ্নিত করেছে।
৫. টুপল এবং প্যাটার্ন ম্যাচিং
স্কালায় Tuple এর সাথে প্যাটার্ন ম্যাচিংও ব্যবহার করা যায়। আপনি টুপলের উপাদানগুলোর সাথে মিলিয়ে কেস চেক করতে পারেন।
উদাহরণ:
object PatternMatchingTuple {
def describeTuple(tuple: (Int, String)): String = tuple match {
case (1, name) => s"First element is 1, second is $name"
case (x, name) => s"First element is $x, second is $name"
}
def main(args: Array[String]): Unit = {
println(describeTuple((1, "Scala"))) // Output: First element is 1, second is Scala
println(describeTuple((2, "Java"))) // Output: First element is 2, second is Java
}
}এখানে:
Tupleএর উপাদানগুলোর সাথে প্যাটার্ন ম্যাচিং করা হচ্ছে, যেখানে প্রথম উপাদান1হলে আলাদা কেস এবং অন্য যেকোনো সংখ্যা জন্য অন্য কেস ব্যবহার করা হচ্ছে।
৬. প্যাটার্ন গার্ড (Pattern Guards)
প্যাটার্ন গার্ড হল একটি অতিরিক্ত শর্ত যা একটি কেসে যোগ করা হয়, যা প্যাটার্ন ম্যাচিং চেক করার সময় একটি নির্দিষ্ট শর্ত সত্য হলে সেই কেস চালু করবে।
উদাহরণ:
object PatternMatchingGuard {
def describeNumber(num: Int): String = num match {
case x if x > 0 => s"$x is a positive number"
case x if x < 0 => s"$x is a negative number"
case _ => "Zero"
}
def main(args: Array[String]): Unit = {
println(describeNumber(10)) // Output: 10 is a positive number
println(describeNumber(-5)) // Output: -5 is a negative number
println(describeNumber(0)) // Output: Zero
}
}এখানে:
ifশর্ত ব্যবহার করে প্যাটার্ন গার্ড যোগ করা হয়েছে, যাতে সংখ্যার পজিটিভ, নেগেটিভ, অথবা শূন্য হওয়া অনুযায়ী আলাদা আউটপুট প্রদর্শিত হয়।
সারাংশ
স্কালায় প্যাটার্ন ম্যাচিং একটি অত্যন্ত শক্তিশালী কনসেপ্ট, যা আপনার কোডকে আরও পরিষ্কার এবং কার্যকরী করে তোলে। এটি match এবং case স্টেটমেন্টের মাধ্যমে ডাটা টাইপ, কন্ডিশন, অথবা কাঠামোর সাথে মিলিয়ে কার্যক্রম নির্ধারণ করতে সাহায্য করে। প্যাটার্ন ম্যাচিং শুধুমাত্র মান নয়, বরং লিস্ট, টুপল, অপশন, এবং অন্যান্য ডাটা স্ট্রাকচারেও কাজ করে। প্যাটার্ন গার্ড ব্যবহার করে আপনি আরও ডাইনামিক এবং শর্তযুক্ত ম্যাচিং তৈরি করতে পারেন।
স্কালায় কেস ক্লাস এবং কেস অবজেক্ট দুটি বিশেষ ধরনের ক্লাস এবং অবজেক্ট, যা মূলত ডাটা হোল্ডিং এবং ডাটা ম্যানিপুলেশন এর জন্য ব্যবহৃত হয়। এগুলি স্কালার ফাংশনাল প্রোগ্রামিং ধারণা অনুসরণ করে এবং অনেক কাজ সহজ করে দেয়। স্কালায় কেস ক্লাস এবং কেস অবজেক্ট ব্যবহার করার ফলে আপনি কম কোডে বেশি কার্যকারিতা পেতে পারেন।
১. কেস ক্লাস (Case Class)
কেস ক্লাস একটি বিশেষ ধরনের ক্লাস যা ডাটা হোল্ডিং এর জন্য ব্যবহৃত হয়। কেস ক্লাস ব্যবহার করার মাধ্যমে আপনি সহজে immutable (অবদলনযোগ্য) ডাটা তৈরি করতে পারেন এবং এর সাথে কিছু বিশেষ ফিচার আসে যা সাধারণ ক্লাসে পাওয়া যায় না, যেমন:
- অটোমেটিক
toStringমেথড। - অটোমেটিক
equalsএবংhashCodeমেথড। - ক্লোনিং (copy) সমর্থন।
- প্যাটার্ন ম্যাচিং এর জন্য উপযুক্ত।
কেস ক্লাস ডেফিনিশন:
case class Person(name: String, age: Int)এখানে:
case classদিয়েPersonনামক একটি কেস ক্লাস তৈরি করা হয়েছে, যেখানে দুটি প্রপার্টিnameএবংageরয়েছে।
কেস ক্লাস ব্যবহার:
object CaseClassExample {
def main(args: Array[String]): Unit = {
// কেস ক্লাস ইনস্ট্যান্স তৈরি
val person1 = Person("Alice", 30)
val person2 = Person("Bob", 25)
// কেস ক্লাসের toString ব্যবহার
println(person1) // Output: Person(Alice,30)
// কেস ক্লাসের copy মেথড ব্যবহার
val person3 = person1.copy(age = 31)
println(person3) // Output: Person(Alice,31)
// equals মেথড
println(person1 == person2) // Output: false
println(person1 == person1) // Output: true
}
}এখানে:
toStringমেথডটি কেস ক্লাসের ইনস্ট্যান্সটি সুস্পষ্টভাবে প্রিন্ট করে।copyমেথডের মাধ্যমে একটি নতুন ইনস্ট্যান্স তৈরি করা হচ্ছে, যেখানে শুধুমাত্রageপরিবর্তন করা হয়েছে।equalsমেথডের মাধ্যমে দুটি কেস ক্লাসের ইনস্ট্যান্সের সমতা পরীক্ষা করা হচ্ছে।
কেস ক্লাসের অন্যান্য ফিচার:
- প্যাটার্ন ম্যাচিং: কেস ক্লাস প্যাটার্ন ম্যাচিংয়ে ব্যবহৃত হয়।
val person = Person("Alice", 30)
person match {
case Person(name, age) => println(s"Name: $name, Age: $age")
}এখানে:
Person(name, age)প্যাটার্ন ম্যাচিং ব্লক ব্যবহার করে কেস ক্লাসের মান এক্সট্র্যাক্ট করা হয়েছে।
২. কেস অবজেক্ট (Case Object)
স্কালায় কেস অবজেক্ট সাধারণত একটি সিঙ্গেলটন (singleton) অবজেক্ট যা প্যাটার্ন ম্যাচিং বা ডেটা হোল্ডিং এর জন্য ব্যবহৃত হয়। কেস অবজেক্ট সাধারণ ক্লাসের মতোই তবে এটি একমাত্র এক ইনস্ট্যান্স থাকে এবং এরও toString, equals এবং hashCode মেথডগুলি অটোমেটিকভাবে তৈরি হয়।
কেস অবজেক্ট ডেফিনিশন:
case object Singletonএখানে:
case objectদিয়েSingletonনামে একটি কেস অবজেক্ট তৈরি করা হয়েছে।
কেস অবজেক্ট ব্যবহার:
object CaseObjectExample {
def main(args: Array[String]): Unit = {
// কেস অবজেক্ট ব্যবহার
println(Singleton) // Output: Singleton
}
}এখানে:
Singletonকেস অবজেক্টের ইনস্ট্যান্সটি একটি একক ইনস্ট্যান্স, এবং তারtoStringমেথডটি স্বয়ংক্রিয়ভাবে"Singleton"রিটার্ন করবে।
কেস অবজেক্টে প্যাটার্ন ম্যাচিং:
object CaseObjectPatternMatching {
def main(args: Array[String]): Unit = {
val obj = Singleton
obj match {
case Singleton => println("Matched the Singleton object")
case _ => println("Didn't match")
}
}
}এখানে:
Singletonকেস অবজেক্টের সাথে প্যাটার্ন ম্যাচিং করা হচ্ছে এবং একটি নির্দিষ্ট ফলাফল রিটার্ন করা হচ্ছে।
৩. কেস ক্লাস এবং কেস অবজেক্টের পার্থক্য
| বৈশিষ্ট্য | কেস ক্লাস (Case Class) | কেস অবজেক্ট (Case Object) |
|---|---|---|
| টাইপ | ডাটা হোল্ডিং এবং ফাংশনাল প্রোগ্রামিং এর জন্য ব্যবহার হয় | সিঙ্গেলটন অবজেক্টের জন্য ব্যবহৃত হয় |
| ইনস্ট্যান্স | একাধিক ইনস্ট্যান্স থাকতে পারে | শুধুমাত্র একটি ইনস্ট্যান্স থাকে |
| প্যাটার্ন ম্যাচিং | প্যাটার্ন ম্যাচিংয়ে ব্যবহৃত হয় | প্যাটার্ন ম্যাচিংয়ে ব্যবহৃত হয় |
| প্রধান ব্যবহার | ডাটা হোল্ডিং এবং ভ্যালু টাইপ ডিফাইন করতে ব্যবহৃত হয় | সিঙ্গেলটন অবজেক্ট এবং স্টেটলেস অপারেশন হ্যান্ডল করার জন্য |
| স্টেট | ইনস্ট্যান্সের স্টেট থাকে | সিঙ্গেল ইনস্ট্যান্স হওয়ায় স্টেট থাকে না |
৪. কেস ক্লাস এবং কেস অবজেক্টের ব্যবহার কোথায় করবেন?
- কেস ক্লাস: যখন আপনার ডেটার সাথে সম্পর্কিত অ্যাকশন এবং ফাংশনালিটি থাকতে হয় এবং আপনি চাইছেন ডাটা হোল্ডিং সহজ এবং ইমিউটেবল হোক, তখন কেস ক্লাস ব্যবহার করা উচিত। যেমন, API রেসপন্স, টিউপল, ভ্যালু টাইপ ইত্যাদি।
- কেস অবজেক্ট: যখন আপনি সিঙ্গেলটন প্যাটার্ন ব্যবহার করতে চান বা কোনো একক ইনস্ট্যান্সে কাজ করতে চান, তখন কেস অবজেক্ট উপযুক্ত।
সারাংশ
- কেস ক্লাস স্কালায় ডাটা হোল্ডিং, ইমিউটেবিলিটি এবং সহজ প্যাটার্ন ম্যাচিংয়ের জন্য ব্যবহৃত হয়।
- কেস অবজেক্ট একক ইনস্ট্যান্সে কাজ করার জন্য এবং সিঙ্গেলটন ব্যবস্থাপনার জন্য ব্যবহৃত হয়।
- কেস ক্লাস এবং কেস অবজেক্টের বিশেষ ফিচার যেমন
toString,equals,hashCode, এবং প্যাটার্ন ম্যাচিং, স্কালাকে আরও শক্তিশালী এবং কার্যকরী করে তোলে।
নেস্টেড প্যাটার্ন (Nested Patterns) স্কালার প্যাটার্ন ম্যাচিং এর একটি শক্তিশালী ফিচার। প্যাটার্ন ম্যাচিং ব্যবহার করে আপনি একটি ভ্যালুর প্যাটার্নের সাথে তুলনা করে সেই ভ্যালুর উপর ভিত্তি করে কোড কার্যকর করতে পারেন। নেস্টেড প্যাটার্ন ব্যবহার করে আপনি একটি প্যাটার্নের ভিতরে আরও প্যাটার্ন ব্যবহার করতে পারেন, অর্থাৎ আপনি একাধিক স্তরের প্যাটার্ন ম্যাচিং করতে পারেন।
নেস্টেড প্যাটার্ন ব্যবহার করার ক্ষেত্রে দুটি মূল কনসেপ্ট:
- টার্নারি প্যাটার্ন (Tuple Pattern): যেখানে আপনি একাধিক মানের জন্য প্যাটার্ন ম্যাচিং করবেন।
- কেস ক্লাস প্যাটার্ন: যেখানে একাধিক স্তরে কেস ক্লাসের মধ্যে প্যাটার্ন ম্যাচিং হবে।
এখানে কিছু উদাহরণ দিয়ে নেস্টেড প্যাটার্ন সম্পর্কে আলোচনা করা হলো।
১. নেস্টেড প্যাটার্নের সাধারণ ব্যবহার
স্কালায় আপনি match ব্লক ব্যবহার করে একটি নেস্টেড প্যাটার্ন তৈরি করতে পারেন, যেখানে আপনি একাধিক স্তরের প্যাটার্ন ম্যাচিং করতে পারেন। উদাহরণস্বরূপ, টুপল বা লিস্টের মধ্যে ভ্যালু ম্যাচ করতে।
১.১ টার্নারি প্যাটার্ন (Tuple Pattern Matching)
এখানে টুপলের ভিতরে একটি ভ্যালুর সাথে প্যাটার্ন ম্যাচিং করা হচ্ছে।
val point = (3, 4)
point match {
case (x, y) if x == y => println("Point is on the line y = x") // When x and y are equal
case (x, y) => println(s"Point is at ($x, $y)") // Default case
}এখানে, টুপলে প্রথম দুটি ভ্যালু (x এবং y) নেস্টেড প্যাটার্ন দিয়ে মেলা হচ্ছে।
আউটপুট:
Point is at (3, 4)১.২ নেস্টেড প্যাটার্ন সহ কেস ক্লাস (Nested Pattern Matching with Case Classes)
আপনি কেস ক্লাসের মধ্যে নেস্টেড প্যাটার্ন ব্যবহার করতে পারেন, যেখানে একাধিক কেস ক্লাস বা সাব ক্লাসের সাথে মেলানো হয়।
sealed trait Animal
case class Dog(name: String, age: Int) extends Animal
case class Cat(name: String, breed: String) extends Animal
val pet: Animal = Dog("Rex", 5)
pet match {
case Dog(name, age) if age > 2 => println(s"$name is an adult dog.") // Nested pattern
case Dog(name, age) => println(s"$name is a puppy.")
case Cat(name, breed) => println(s"$name is a $breed cat.")
}এখানে, কেস ক্লাসের মধ্যে নেস্টেড প্যাটার্ন ব্যবহার করে Dog এবং Cat এর ভ্যালু মেলা হচ্ছে। Dog এর বয়স চেক করা হচ্ছে এবং বয়স অনুযায়ী প্যাটার্ন ম্যাচ করা হচ্ছে।
আউটপুট:
Rex is an adult dog.১.৩ লিস্ট প্যাটার্ন ম্যাচিং
নেস্টেড প্যাটার্নের একটি সাধারণ উদাহরণ হল লিস্টের ভিতরে উপাদানগুলির উপর প্যাটার্ন ম্যাচিং করা। এখানে, আপনি একটি লিস্টের প্রথম উপাদান এবং বাকি উপাদানগুলির উপর প্যাটার্ন ম্যাচ করতে পারেন।
val numbers = List(1, 2, 3, 4)
numbers match {
case List(1, x, y, z) => println(s"List starts with 1 and the next elements are: $x, $y, $z")
case List(1, _*) => println("List starts with 1, but the rest is unknown")
case _ => println("No match")
}এখানে, প্রথম উপাদান চেক করা হচ্ছে এবং বাকি উপাদানগুলোর উপর প্যাটার্ন ম্যাচ করা হচ্ছে।
আউটপুট:
List starts with 1 and the next elements are: 2, 3, 4১.৪ নেস্টেড প্যাটার্ন সহ অপশনাল টাইপ
স্কালায় Option টাইপও নেস্টেড প্যাটার্নের জন্য ব্যবহার করা যায়, যেখানে Some এবং None কে পৃথকভাবে চেক করা হয়।
val maybeNumber: Option[Int] = Some(42)
maybeNumber match {
case Some(x) if x > 40 => println(s"Number is greater than 40: $x") // Nested pattern inside Some
case Some(x) => println(s"Number is: $x")
case None => println("No number provided")
}এখানে, Some(x) ভিতরের ভ্যালু চেক করা হচ্ছে এবং একটি নির্দিষ্ট শর্ত (যেমন 40 এর বেশি) পূরণ হলে একটি পৃথক আউটপুট প্রদান করা হচ্ছে।
আউটপুট:
Number is greater than 40: 42২. নেস্টেড প্যাটার্নের সুবিধা এবং ব্যবহার
- কোডের পাঠযোগ্যতা: নেস্টেড প্যাটার্ন আপনাকে জটিল ডেটা স্ট্রাকচারের মধ্যে সহজেই প্যাটার্ন ম্যাচ করতে সাহায্য করে, ফলে কোড আরও পরিষ্কার এবং সংক্ষিপ্ত হয়।
- ডেটার গভীরে কাজ করার ক্ষমতা: যখন ডেটার গভীরে কাজ করতে হয় (যেমন টুপল, লিস্ট, অপশন, কেস ক্লাস), তখন নেস্টেড প্যাটার্ন খুবই উপকারী।
- ফাংশনাল প্রোগ্রামিং: নেস্টেড প্যাটার্ন ফাংশনাল প্রোগ্রামিংয়ের জন্য খুবই শক্তিশালী একটি টুল, যেখানে আপনি ডেটার প্রতিটি স্তরের উপর কাজ করতে পারেন।
সারাংশ
- নেস্টেড প্যাটার্ন হল একটি শক্তিশালী প্যাটার্ন ম্যাচিং কৌশল যেখানে আপনি একাধিক স্তরের ডেটা স্ট্রাকচারের উপর প্যাটার্ন ম্যাচ করতে পারেন।
- এটি টুপল, লিস্ট, কেস ক্লাস এবং অপশনাল টাইপের মতো ডেটা স্ট্রাকচারে কার্যকরীভাবে কাজ করতে ব্যবহৃত হয়।
- স্কালার
matchব্লক এবংcaseপ্যাটার্ন স্টেটমেন্ট ব্যবহার করে নেস্টেড প্যাটার্ন তৈরি করা যায়।
নেস্টেড প্যাটার্ন স্কালার ফাংশনাল প্রোগ্রামিংয়ের এক গুরুত্বপূর্ণ এবং শক্তিশালী কনসেপ্ট, যা কোডের কার্যকারিতা বৃদ্ধি করতে এবং ডেটা ম্যানিপুলেশন সহজ করতে সাহায্য করে।
গার্ড ক্লজ (Guard Clauses) হল একটি কোডিং প্যাটার্ন যেখানে একটি নির্দিষ্ট শর্তের ভিত্তিতে প্রোগ্রাম ফ্লো প্রাথমিকভাবে বেরিয়ে যায় বা অন্যভাবে কাজ শুরু করে। গার্ড ক্লজ সাধারণত কোডের প্রাথমিক শর্তাবলী যাচাই করার জন্য ব্যবহৃত হয়, এবং এটি কোডের পাঠযোগ্যতা উন্নত করতে সহায়তা করে।
স্কালায় গার্ড ক্লজ সাধারণত if শর্ত বা match স্টেটমেন্টের সাথে ব্যবহৃত হয়, যেখানে আগেই শর্ত যাচাই করা হয় এবং তারপরে শর্ত মেলে না এমন পরিস্থিতিতে কোডের পরবর্তী অংশ সম্পাদিত হয়।
গার্ড ক্লজের সুবিধা
- কোডের পাঠযোগ্যতা বাড়ায়।
- শর্তের ভিত্তিতে কোডের কার্যক্রম দ্রুত প্রত্যাখ্যান (early exit) করতে সহায়তা করে।
- লজিকাল কমপ্লেক্সিটি কমায়, কারণ কোডের শর্তগুলো একে অপরের থেকে আলাদা এবং পরিষ্কারভাবে উল্লেখ করা থাকে।
১. if শর্ত ব্যবহার করে গার্ড ক্লজ
স্কালায় গার্ড ক্লজ ব্যবহারের সবচেয়ে সহজ পদ্ধতি হল if শর্ত ব্যবহার করে। এখানে আমরা কোডের প্রথমে শর্ত যাচাই করব এবং যদি শর্ত মেলে না, তাহলে ফাংশন বা মেথডটি return করবে।
উদাহরণ:
object GuardClauseExample {
def processNumber(number: Int): Unit = {
// Guard clause to handle invalid input
if (number <= 0) {
println("Invalid number, must be positive!")
return
}
// Main logic, will only run if the number is positive
println(s"Processing number: $number")
}
def main(args: Array[String]): Unit = {
processNumber(-5) // Output: Invalid number, must be positive!
processNumber(10) // Output: Processing number: 10
}
}এখানে:
- গার্ড ক্লজ হিসেবে
if (number <= 0)চেক করা হয়েছে। যদি ইনপুট নম্বরটি ০ বা তার কম হয়, তাহলে ফাংশনটি প্রথমেই বেরিয়ে যাবে (return) এবং পরবর্তী কোড এক্সিকিউট হবে না। - যদি ইনপুটটি বৈধ হয়, তাহলে মূল প্রক্রিয়া (
println(s"Processing number: $number")) কার্যকর হবে।
২. match স্টেটমেন্টে গার্ড ক্লজ ব্যবহার
স্কালায় match স্টেটমেন্টেও গার্ড ক্লজ ব্যবহার করা যায়, যেখানে একটি নির্দিষ্ট শর্তের ভিত্তিতে কোড ফ্লো নির্ধারণ করা হয়।
উদাহরণ:
object GuardClauseWithMatch {
def describeNumber(number: Int): String = number match {
case n if n <= 0 => "Number must be positive!"
case n if n > 0 && n <= 10 => "Number is between 1 and 10"
case n if n > 10 => "Number is greater than 10"
}
def main(args: Array[String]): Unit = {
println(describeNumber(-5)) // Output: Number must be positive!
println(describeNumber(7)) // Output: Number is between 1 and 10
println(describeNumber(20)) // Output: Number is greater than 10
}
}এখানে:
matchস্টেটমেন্টে গার্ড ক্লজ হিসেবেifব্যবহার করা হয়েছে, যেখানে বিভিন্ন শর্ত অনুযায়ী ভিন্ন ভিন্ন আউটপুট দেওয়া হচ্ছে।n <= 0শর্তের মাধ্যমে যদি নম্বরটি নেতিবাচক বা শূন্য হয়, তবে প্রথম আউটপুট প্রদান করা হবে। অন্যথায়, অন্যান্য শর্ত অনুযায়ী আউটপুট দেওয়া হবে।
৩. গার্ড ক্লজের অন্যান্য ব্যবহার
গার্ড ক্লজে আমরা শর্তটি সরাসরি কোডের শুরুতে উল্লেখ করে পরে মূল কার্যক্রম সম্পাদন করি। এটি সাধারণত ছোট ফাংশনে বা ফাংশনাল প্রোগ্রামিং প্যাটার্নে ব্যবহৃত হয়, যেখানে কোডের শর্ত যাচাই করা খুবই গুরুত্বপূর্ণ।
উদাহরণ:
object GuardClauseExample {
def calculateDiscount(price: Double): Double = {
// Guard clause for invalid price
if (price <= 0) {
println("Invalid price!")
return 0
}
// Calculate discount based on price
if (price > 100) {
price * 0.2 // 20% discount for prices over 100
} else {
price * 0.1 // 10% discount for prices 100 or below
}
}
def main(args: Array[String]): Unit = {
println(calculateDiscount(-50)) // Output: Invalid price! 0
println(calculateDiscount(150)) // Output: 30.0
}
}এখানে:
- গার্ড ক্লজ হিসেবে
if (price <= 0)চেক করা হয়েছে, যাতে নেতিবাচক মূল্য প্রাপ্ত হলে প্রোগ্রামটি আগে থেকেই চলে যায় এবং কোন ডেলিভারি বা ডিসকাউন্ট ক্যালকুলেশন না হয়। - পরবর্তী শর্তগুলিতে
priceএর ভিত্তিতে ডিসকাউন্ট নির্ধারণ করা হচ্ছে।
৪. গার্ড ক্লজের সুবিধা
- কোড পরিষ্কার এবং সংক্ষিপ্ত: গার্ড ক্লজ ব্যবহারের ফলে কোড আরও পরিষ্কার এবং পাঠযোগ্য হয়। আপনি কোডের শুরুতেই শর্ত যাচাই করতে পারেন এবং পরবর্তী কোডটি শুধুমাত্র শর্ত পূর্ণ হলে চলবে।
- নিরাপত্তা বৃদ্ধি: গার্ড ক্লজ ডেটার ইনপুট বা কন্ডিশনের নিরাপত্তা নিশ্চিত করতে সহায়তা করে, যেমন যদি অকার্যকর বা অবৈধ ডেটা থাকে তবে কোডটি ব্যর্থ হতে না দিয়ে প্রাথমিকভাবে বেরিয়ে যায়।
- লজিকাল কমপ্লেক্সিটি কমায়: গার্ড ক্লজ কোডের লজিক সহজ করতে সহায়তা করে, কারণ এতে একাধিক
ifবাmatchব্লক একত্রে চেক করা হয় এবং কোডের অন্যান্য অংশে দ্রুত প্রবেশ করা হয়।
সারাংশ
গার্ড ক্লজ (Guard Clauses) হল কোডের একটি কার্যকর প্যাটার্ন যা কোডের মধ্যে প্রাথমিক শর্ত যাচাই করে এবং সেই শর্ত না মেলে থাকলে দ্রুত বেরিয়ে যেতে সহায়তা করে। এটি কোডের নিরাপত্তা, পরিষ্কারতা এবং কার্যকারিতা বৃদ্ধি করে। স্কালায় if বা match স্টেটমেন্টের মাধ্যমে গার্ড ক্লজ ব্যবহার করা হয় এবং এটি কোডের জটিলতা কমাতে সাহায্য করে।
স্কালায় প্যাটার্ন ম্যাচিং একটি শক্তিশালী ফিচার, যা কোডকে আরও পরিষ্কার এবং কার্যকরী করে তোলে। এটি স্কালার ফাংশনাল প্রোগ্রামিং প্যারাডাইমের একটি প্রধান অংশ, যা ডাটা স্ট্রাকচার বা ভ্যালুগুলির উপর ভিত্তি করে বিভিন্ন কন্ডিশন অনুসারে কার্য সম্পাদন করতে সাহায্য করে। স্কালায় সাধারণ প্যাটার্ন ম্যাচিং এর পাশাপাশি অ্যাডভান্সড প্যাটার্ন ম্যাচিং কৌশলগুলো কোড লেখাকে আরও শক্তিশালী এবং নমনীয় করে তোলে।
এই লেখায় আমরা স্কালার অ্যাডভান্সড প্যাটার্ন ম্যাচিং কৌশলগুলো সম্পর্কে বিস্তারিত জানবো।
১. কেস ক্লাউজ (Case Class) এবং প্যাটার্ন ম্যাচিং
স্কালায় case class এর সাথে প্যাটার্ন ম্যাচিং ব্যবহার করা হয় খুবই শক্তিশালীভাবে, কারণ case class-এ ডিফাইন করা ডাটা সহজেই প্যাটার্ন ম্যাচিংয়ের জন্য প্রোসেস করা যায়।
উদাহরণ:
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(length: Double, width: Double) extends Shape
def area(shape: Shape): Double = shape match {
case Circle(r) => Math.PI * r * r
case Rectangle(l, w) => l * w
}
val circle = Circle(5)
val rectangle = Rectangle(4, 6)
println(area(circle)) // Output: 78.53981633974483
println(area(rectangle)) // Output: 24.0এখানে:
Shapeএকটি sealed trait এবং এর দুটি case class (CircleএবংRectangle) তৈরি করা হয়েছে।- প্যাটার্ন ম্যাচিংয়ে
CircleএবংRectangleএর ভ্যালুগুলোকে ভিন্নভাবে প্রক্রিয়া করা হচ্ছে।
sealed trait ব্যবহার করার সুবিধা:
- এটি নিশ্চিত করে যে,
Shapeএর সব সাবক্লাসগুলোই কোডে ডিফাইন করা থাকবে। এর ফলে কম্পাইলার আপনাকেmatchব্লক লেখার সময় সব কেস চেক করতে সাহায্য করবে।
২. উপাদানসমূহের উপর প্যাটার্ন ম্যাচিং (Matching on Elements)
স্কালায় প্যাটার্ন ম্যাচিং বিভিন্ন ডাটা স্ট্রাকচার যেমন লিস্ট, টিউপল, অ্যারে ইত্যাদির উপাদানগুলির উপর কাজ করতে পারে। এখানে একাধিক উপাদানের সাথে match ব্যবহার করা হয়।
উদাহরণ:
val numbers = List(1, 2, 3)
val result = numbers match {
case List(1, 2, 3) => "Matched the pattern 1, 2, 3"
case List(1, _*) => "Starts with 1"
case _ => "No match"
}
println(result) // Output: Matched the pattern 1, 2, 3এখানে:
List(1, 2, 3): এটি সম্পূর্ণভাবে মেলানো হচ্ছে এবং "Matched the pattern 1, 2, 3" আউটপুট হচ্ছে।List(1, _*): এটি একটি আংশিক মেলানো প্যাটার্ন যেখানে লিস্টের প্রথম উপাদানটি1হতে হবে এবং বাকি উপাদানগুলো যে কোনো কিছু হতে পারে।
৩. গার্ড কন্ডিশন (Guard Condition)
গার্ড কন্ডিশন প্যাটার্ন ম্যাচিংয়ের একটি গুরুত্বপূর্ণ অংশ, যা আপনাকে প্যাটার্ন ম্যাচিংয়ের সাথে অতিরিক্ত শর্ত বা কন্ডিশন চেক করতে দেয়। গার্ড কন্ডিশন সাধারণত if বা require বা guard ব্যবহার করে যোগ করা হয়।
উদাহরণ:
val x = 15
val result = x match {
case x if x % 2 == 0 => "Even"
case x if x % 2 != 0 => "Odd"
case _ => "Unknown"
}
println(result) // Output: Oddএখানে:
case x if x % 2 == 0: এখানে গার্ড কন্ডিশন ব্যবহার করা হয়েছে, যাতেxযদি সঠিকভাবে ইভেন হয়, তবে প্যাটার্ন ম্যাচ হবে।case x if x % 2 != 0: এখানে গার্ড কন্ডিশন দিয়ে আন্ডারলাইন করা হয়েছে যে,xযদি ইমপেয়ার হয় তবে "Odd" হবে।
৪. টিউপল এবং লিস্ট প্যাটার্ন ম্যাচিং
স্কালায় টিউপল বা লিস্ট এর উপাদানগুলোর উপরও প্যাটার্ন ম্যাচিং করা যেতে পারে।
উদাহরণ:
val point = (3, 4)
val result = point match {
case (0, 0) => "Origin"
case (x, y) if x == y => "On the line x = y"
case (x, y) => s"Point is at ($x, $y)"
}
println(result) // Output: Point is at (3, 4)এখানে:
case (0, 0): প্রথম উপাদান (x) এবং দ্বিতীয় উপাদান (y) যদি ০ হয়, তবে এটি "Origin" চিহ্নিত করবে।case (x, y) if x == y: এই কেসটি তখনই ম্যাচ হবে যখন x এবং y সমান হবে।case (x, y): সবগুলো কেসে ডিফল্ট হিসেবে(x, y)থাকবে এবং এটি সঠিকভাবে মূল্যায়ন করবে।
৫. কোলেকশন প্যাটার্ন ম্যাচিং (Matching Collections)
স্কালায় প্যাটার্ন ম্যাচিং কোলেকশনগুলোর উপরও কাজ করতে পারে, এবং এতে আপনি :: (প্রথম এলিমেন্ট এবং বাকি এলিমেন্ট) বা Nil (খালি লিস্ট) ব্যবহার করতে পারেন।
উদাহরণ:
val numbers = List(1, 2, 3, 4)
val result = numbers match {
case Nil => "Empty list"
case x :: xs => s"First element is $x, rest are $xs"
}
println(result) // Output: First element is 1, rest are List(2, 3, 4)এখানে:
case Nil: এটি একটি খালি লিস্টের জন্য।case x :: xs: এটি একটি লিস্টের প্রথম উপাদান এবং বাকি উপাদানগুলিকে আলাদা করতে ব্যবহৃত হয়।xহল প্রথম এলিমেন্ট এবংxsহল বাকি এলিমেন্টের লিস্ট।
৬. অ্যাডভান্সড প্যাটার্ন ম্যাচিং কৌশল
- কেস ক্লাসের সাথে প্যাটার্ন ম্যাচিং: আপনি কেস ক্লাসের জন্য স্বয়ংক্রিয়ভাবে প্যাটার্ন ম্যাচিং করতে পারেন এবং ক্লাসের ভ্যালু সহজেই এক্সট্র্যাক্ট করতে পারেন।
- প্যাটার্ন গার্ডস: প্যাটার্ন ম্যাচিংয়ের শর্তযুক্ত সিদ্ধান্ত গ্রহণের জন্য গার্ড কন্ডিশন ব্যবহার করা হয়।
- স্ট্রাকচারাল প্যাটার্ন ম্যাচিং: নতুন স্কালা 3 এ স্ট্রাকচারাল প্যাটার্ন ম্যাচিং ফিচার এসেছে, যেখানে আপনি ক্লাসের ভ্যালু ডিরেক্টলি এক্সট্র্যাক্ট করতে পারবেন।
সারাংশ
- স্কালা প্যাটার্ন ম্যাচিং হলো একটি শক্তিশালী এবং নমনীয় কৌশল, যা ডাটা স্ট্রাকচার বা ভ্যালু অনুযায়ী সহজে কোডের কার্যকারিতা নির্ধারণ করতে সাহায্য করে।
- অ্যাডভান্সড প্যাটার্ন ম্যাচিং-এর মাধ্যমে আপনি কেস ক্লাস, গার্ড কন্ডিশন, কোলেকশন প্যাটার্ন, টিউপল ইত্যাদি ব্যবহার করে আরও জটিল এবং শক্তিশালী ম্যাচিং করতে পারেন।
Read more