Scala Tutorial
Basics
Control Statements
OOP Concepts
Parameterized - Type
Exceptions
Scala Annotation
Methods
String
Scala Packages
Scala Trait
Collections
Scala Options
Miscellaneous Topics
Scala extractors are objects that have an unapply
method. They can be used in pattern matching to destructure objects. Extractors allow for custom patterns beyond simple case class decomposition.
For an object to be used as an extractor, it should define an unapply
method. The method should return an Option
containing the decomposed values if they match the expected pattern and None
if they don't.
Here's a simple example:
object Even { def unapply(x: Int): Option[Int] = if (x % 2 == 0) Some(x) else None } val number = 4 number match { case Even(n) => println(s"$n is even.") case _ => println(s"$number is odd.") }
In this example, if number
is even, the pattern Even(n)
will match, and n
will bind to the even number.
You can return multiple values by using tuples:
object Name { def unapply(str: String): Option[(String, String)] = { val parts = str.split(" ") if (parts.length == 2) Some(parts(0), parts(1)) else None } } "John Doe" match { case Name(first, last) => println(s"First Name: $first, Last Name: $last") case _ => println("Name didn't match the pattern.") }
unapplySeq
For sequences, unapplySeq
can be defined:
object Names { def unapplySeq(str: String): Option[Seq[String]] = { val parts = str.split(" ") if (parts.length > 0) Some(parts) else None } } "John Jacob Jingleheimer Schmidt" match { case Names(first, rest @ _*) => println(s"First Name: $first, Other Names: ${rest.mkString(", ")}") }
In this example, the @_*
is a pattern that matches the rest of the sequence.
Reusability: Extractors can be reused across multiple classes and are not tied to a particular class, unlike case class decomposition.
Abstraction: Extractors allow abstracting away the details of object construction and decomposition. This is useful in scenarios where how you want to pattern match an object is different from how it's constructed.
Flexibility: Since the unapply
method returns an Option
, extractors have the flexibility to determine which objects they can successfully destructure and which they can't.
In summary, extractors in Scala provide a way to define custom patterns for pattern matching, adding to the expressiveness and flexibility of the language.
Custom Extractors in Scala:
Define custom extractors for your own data types.
object Email { def unapply(email: String): Option[(String, String)] = { val parts = email.split("@") if (parts.length == 2) Some(parts(0), parts(1)) else None } }
Extractor Objects in Scala:
Extractors are often defined as objects with an unapply
method.
object Even { def unapply(x: Int): Option[Int] = if (x % 2 == 0) Some(x) else None }
Unapply Method in Scala Extractors:
The unapply
method in extractors defines the pattern-matching logic.
object Name { def unapply(fullName: String): Option[(String, String)] = { val parts = fullName.split(" ") if (parts.length == 2) Some(parts(0), parts(1)) else None } }
Extracting Values with Pattern Matching in Scala:
Use pattern matching to extract values using extractors.
val email = "john.doe@example.com" email match { case Email(user, domain) => println(s"User: $user, Domain: $domain") case _ => println("Invalid email format") }
Matching Multiple Values with Extractors in Scala:
Combine multiple extractors in a single pattern match.
val input = "John Doe" input match { case Name(firstName, lastName) => println(s"First: $firstName, Last: $lastName") case Email(user, domain) => println(s"User: $user, Domain: $domain") case _ => println("Unknown pattern") }
Using Extractors for Case Class Deconstruction in Scala:
Case classes automatically have an extractor generated for them.
case class Person(name: String, age: Int) val person = Person("John", 25) person match { case Person(name, age) => println(s"Name: $name, Age: $age") case _ => println("Not a Person") }