
- Scala - Home
- Scala - Overview
- Scala - Features
- Scala - Environment Setup
- Scala - Build Tool (SBT)
- Scala - REPL
- Scala - Dot & Dotty
- Scala - Basic Syntax
- Scala - Hello World Program
- Scala - Identifiers
- Scala - Keywords
- Scala - Comments
- Scala - Code Blocks
- Scala - Semicolon
- Scala - Constructs
- Scala - Expressions
- Scala - Input and Output
- Scala - Optional Braces
- Scala - Underscore (_)
- Data Types and Variables
- Scala - Data Types
- Scala - Type Bounds
- Scala - Context Bound
- Scala - Variances
- Scala - Type Hierarchy
- Scala - Variables
- Scala - Variable Scopes
- Scala - Literals
- Scala - Numeric Types
- Scala - Boolean Types
- Scala - Char Type
- Scala - Unit Types
- Scala - Strings
- Scala - Arrays
- Scala - Null Type
- Scala - Nothing
- Scala - Any Type
- Scala - AnyRef Type
- Scala - Unified Types
- Scala - Dates and Times
- Scala - Ranges
- Scala - Multidimensional Arrays
- Scala - WrappedArray
- Scala - StringBuilder
- Scala - String Interpolation
- Scala - StringContext
- Scala - Type Casting
- Scala var vs val
- Scala Operators
- Scala - Operators
- Scala - Rules for Operators
- Scala - Arithmetic Operators
- Scala - Relational Operators
- Scala - Logical Operators
- Scala - Bitwise Operators
- Scala - Assignment Operators
- Scala - Operators Precedence
- Scala - Symbolic Operators
- Scala - Range Operator
- Scala - String Concatenation Operator
- Scala Conditional Statements
- Scala - IF ELSE
- Scala - IF-ELSE-IF-ELSE Statement
- Scala - Nested IF-ELSE Statement
- Scala Loop Statements
- Scala - Loop Statements
- Scala - while Loop
- Scala - do-while Loop
- Scala - Nested Loops
- Scala - for Loop
- Scala - break Statement
- Scala - yield Keyword
- Scala Classes & Objects
- Scala - Classes & Objects
- Scala - Constructors
- Scala - Auxiliary Constructor
- Scala - Primary Constructor
- Scala - This Keyword
- Scala - Nested Classes
- Scala - Getters and Setters
- Scala - Object Private Fields
- Scala - Singleton Object
- Scala - Companion Objects
- Scala - Creating Executable Programs
- Scala - Stateful Object
- Scala - Enumerations
- Scala - Polymorphism
- Scala - Access Modifiers
- Scala - Apply Method
- Scala - Update Methods
- Scala - UnapplySeq Method
- Scala - Inheritance
- Scala - Extending a Class
- Scala - Method Overloading
- Scala - Method Overriding
- Scala - Generic Classes
- Scala - Generic Functions
- Scala - Superclass Construction
- Scala Methods & Functions
- Scala - Methods
- Scala - Functions
- Scala - Methods vs Functions
- Scala - Main Methods
- Scala - Functions Call-by-Name
- Scala - Functions with Named Arguments
- Scala - Function with Variable Arguments
- Scala - Recursion Functions
- Scala - Default Parameter Values
- Scala - Functions without Parameters
- Scala - Implicit Parameters
- Scala - Higher-Order Functions
- Scala - Nested Functions
- Scala - Extension Methods
- Scala - Anonymous Functions
- Partially Applied Functions
- Scala - Lazy Val
- Scala - Pure Function
- Scala - Currying Functions
- Scala - Control Abstractions
- Scala - Corecursion
- Scala - Unfold
- Scala - Tail Recursion
- Scala - Infinite Sequences
- Scala - Dynamic Invocation
- Scala - Lambda Expressions
- Scala - Polymorphic Functions
- Scala Collections
- Scala - Collections
- Mutable and Immutable Collections
- Scala - Lists
- Scala - Sets
- Scala - Maps
- Scala - TreeMap
- Scala - SortedMap
- Scala - Tuples
- Scala - Iterators
- Scala - Options
- Scala - NumericRange
- Scala - Infinite Streams
- Scala - Parallel Collections
- Scala Advanced Types
- Scala - Union Types
- Scala - Intersection Types
- Scala - Type Aliases
- Scala - Structural Types
- Scala - Match Expression
- Scala - Singleton Type Operator
- Scala - Abstract Types
- Scala - Dependent Types
- Scala - Abstract Type Bounds
- Scala - Higher-Kinded Types
- Scala - Opaque Type Alias
- Scala - Path-Dependent Types
- Scala - Type Lambdas
- Scala - Type Inference
- Scala - Algebraic Data Types
- Scala Pattern Matching
- Scala - Pattern Matching
- Scala - Guards
- Scala - Variables in Patterns
- Scala - Type Patterns
- Scala - The Matchable Trait
- Scala - Matching Arrays
- Scala - Matching Lists
- Scala - Matching Tuples
- Scala - Exception Handling
- Scala - Extractors
- Scala - Pattern Bindings
- Scala - Regular Expressions
- Scala - Case Classes
- Scala - Partial Functions
- Scala - Packaging and Imports
- Scala - Implicit Imports
- Scala - Export Clauses
- Scala - Nested Packages
- Scala - Chained Packages
- Scala - Package Objects
- Scala Files I/O
- Scala - Files I/O
- Scala - Writing Files
- Scala - Listing Files
- Scala - Deleting Directories
- Scala - Check File Exists
- Scala Advanced Concepts
- Scala - Closures
- Scala - Futures
- Scala - Promises
- Scala - Traits
- Scala - Trait Mixins
- Scala - Layered Traits
- Scala - Trait Linearization
- Scala - Sealed Traits
- Scala - Transparent Traits
- Scala - Process Management
- Scala - Scaladoc
- Scala - Literal Type Arithmetic
- Scala - Inline keyword
- Scala - Def, Var & Val
- Scala - Dropped Features
- Scala Unit Testing
- Scala - Unit Testing
- Scala - uTest
- Scala - MUnit
- Scala - ScalaTest Runner
- Scala - ScalaMock
- Scala - JUnit
- Scala - Mocking
- Scala - BDD Testing
Scala - Extractors
An extractor in Scala is an object that has a method called unapply as one of its members. The purpose of that unapply method is to match a value and take it apart. Often, the extractor object also defines a dual method apply for building values, but this is not required.
Example
Let us take an example of object defines both apply and unapply methods. The apply method has the same meaning as always: it turns Test into an object that can be applied to arguments in parentheses in the same way a method is applied. So you can write Test ("Zara", "gmail.com") to construct the string "Zara@gmail.com".
The unapply method is what turns Test class into an extractor and it reverses the construction process of apply. Where apply takes two strings and forms an email address string out of them, unapply takes an email address and returns potentially two strings: the user and the domain of the address.
The unapply must also handle the case where the given string is not an email address. That's why unapply returns an Option-type over pairs of strings. Its result is either Some (user, domain) if the string str is an email address with the given user and domain parts, or None, if str is not an email address. Here are some examples as follows.
Syntax
unapply("Zara@gmail.com") equals Some("Zara", "gmail.com") unapply("Zara Ali") equals None
Extractor Object for Email Addresses
The following example program shows an extractor object for email addresses.
Example
object Demo { def main(args: Array[String]) = { println ("Apply method : " + apply("Zara", "gmail.com")); println ("Unapply method : " + unapply("Zara@gmail.com")); println ("Unapply method : " + unapply("Zara Ali")); } // The injection method (optional) def apply(user: String, domain: String) = { user +"@"+ domain } // The extraction method (mandatory) def unapply(str: String): Option[(String, String)] = { val parts = str split "@" if (parts.length == 2){ Some(parts(0), parts(1)) } else { None } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Apply method : Zara@gmail.com Unapply method : Some((Zara,gmail.com)) Unapply method : None
Pattern Matching with Extractors
When an instance of a class is followed by parentheses with a list of zero or more parameters, the compiler invokes the apply method on that instance. We can define apply both in objects and in classes.
As mentioned above, the purpose of the unapply method is to extract a specific value we are looking for. It does the opposite operation apply does. When comparing an extractor object using the match statement the unapply method will be automatically executed.
Example
Try the following example program −
object Demo { def main(args: Array[String]) = { val x = Demo(5) println(x) x match { case Demo(num) => println(x+" is bigger two times than "+num) //unapply is invoked case _ => println("i cannot calculate") } } def apply(x: Int) = x*2 def unapply(z: Int): Option[Int] = if (z%2==0) Some(z/2) else None }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
10 10 is bigger two times than 5
Extractors with Case Classes
Case classes in Scala automatically come with an apply method and an unapply method. Ao case classes are very convenient for pattern matching.
Example
Consider the following case class Person:
Let us take an example of a case class Person that defines both apply and unapply methods. The apply method has the same meaning as always: it turns Person into an object that can be applied to arguments in parentheses in the same way a method is applied. So you can write Person("Nuha", 25) to construct a Person instance.
The unapply method is what turns the Person class into an extractor and it reverses the construction process of apply. Where apply takes two arguments and forms a Person instance out of them, unapply takes a Person instance and returns potentially two values: the name and the age.
The unapply must also handle the case where the given object is not a Person instance. That's why unapply returns an Option-type over pairs of values. Its result is either Some(name, age) if the object is a Person with the given name and age, or None, if the object is not a Person. Here are some examples as follows.
Syntax
unapply(Person("Nuha", 25)) equals Some("Nuha", 25) unapply("Not a person") equals None
Following example program shows an extractor object for Person case class.
Example
case class Person(name: String, age: Int) object Demo { def main(args: Array[String]) = { val person = Person("Nuha", 25) person match { case Person(n, a) => println(s"Name: $n, Age: $a") case _ => println("Not a person") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
Name: Nuha, Age: 25
In this example, the Person case class is matched and its fields are extracted using the automatically provided unapply method.
Custom Extractors with Guards
Extractors can also be enhanced with more logic using guards for more matching cases.
Example
Consider an extractor that matches even numbers:
Let us take an example of an object Even that defines the unapply method. The unapply method checks if a given number is even. If it is, it returns Some with the number, otherwise, it returns None.
Syntax
unapply(4) equals Some(4) unapply(5) equals None
Following example program shows a custom extractor object for even numbers.
Example
object Even { def unapply(x: Int): Option[Int] = if (x % 2 == 0) Some(x) else None } object Demo { def main(args: Array[String]) = { val num = 4 num match { case Even(n) => println(s"$n is an even number") case _ => println(s"$num is not an even number") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
4 is an even number
In this example, the Even extractor uses a guard to check if a number is even and matches accordingly.
Chained Extractors
Extractors can also be chained to match complex data structures in a sequence.
Example
Consider an extractor for domain-specific email addresses:
Let us take an example of an object DomainExtractor that defines the unapply method. The unapply method splits an email address into user and domain parts and checks if the domain is "domain.com". If it is, it returns Some with the user and domain parts, otherwise, it returns None.
Syntax
unapply("maira@domain.com") equals Some("maira", "domain.com") unapply("maira@gmail.com") equals None
Following example program shows a chained extractor object for domain-specific email addresses.
Example
object DomainExtractor { def unapply(email: String): Option[(String, String)] = { val parts = email.split("@") if (parts.length == 2 && parts(1) == "domain.com") Some(parts(0), parts(1)) else None } } object Demo { def main(args: Array[String]) = { val email = "maira@domain.com" email match { case DomainExtractor(user, domain) => println(s"User: $user, Domain: $domain") case _ => println("Not a valid domain email") } } }
Save the above program in Demo.scala. Use the following commands to compile and execute this program.
Command
> scalac Demo.scala > scala Demo
Output
User: maira, Domain: domain.com
In this example, the DomainExtractor object matches emails specifically from "domain.com" and extracts the user part.
Extractors Summary
- Extractors are objects that define unapply methods for pattern matching and decomposing values.
- The apply method is optional and used for constructing values. Whereas unapply is mandatory for extracting values.
- Extractors return Option types, with Some for successful matches and None for failures.
- Extractors can be used in match expressions for pattern matching.
- Case classes automatically provide apply and unapply methods. So case classes are easy and convenient for pattern matching.
- Custom extractors can include guards to add conditional logic to pattern matching.
- You can chain extractors to match and decompose nested data structures.