Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching on big/long case classes

Is there a more readable and and more robust (to refactoring) way to match on case classes like this ?

Example

Case Class

Very long case class with many "fields".

case class Data(name: String, time: Long, ..., userId: Option[UUID] ..., orders: Int, ... ) //more fields fields more

Pattern match: Variant a

Works. But error prone when fields position changes. One ends up counting _.

res match {
  case data@Data(_,_,_,_,_,_,Some(id),_,_,_,6,_,_) => (id, data.orders)
  case _ => ... 

} 

Pattern match: Variant b

Works also. Is stable to changing orders. Gets really cumbersome with more checks in the guard. Also reading the value has to be repeated.

res match {
  case data: Data if data.userId.isDefined && data.orders == 6 => (data.userId.get,data.orders)
  case _ => ...
} 

Question rephrased

Is there a way to combine Variant A and B to get the benefit of both approaches ?

like image 317
Andreas Neumann Avatar asked Aug 25 '16 08:08

Andreas Neumann


People also ask

Which method of case class allows using objects in pattern matching?

The match method takes a number of cases as an argument. Each alternative takes a pattern and one or more expressions that will be performed if the pattern matches.

What is Scala pattern matching?

Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.

How does pattern matching work?

Pattern Matching works by "reading" through text strings to match patterns that are defined using Pattern Matching Expressions, also known as Regular Expressions. Pattern Matching can be used in Identification as well as in Pre-Classification Processing, Page Processing, or Storage Processing.

Can a case class extend a trait?

A Case Class or Case Object can extend a Trait. Create a trait using trait keyword which contains methods you want the inherited classes to implement.


1 Answers

You can use a custom extractor:

res match {
  case ExtractUserIdAndOrders(Some(id), 6) => ...
  case _ => ...
}

where

object ExtractUserIdAndOrders {
  def unapply(data: Data) = Some((data.userId, data.orders))
}

You can define it inside the method if you need it just once, or in a wider scope for multiple similar matches.

like image 188
Alexey Romanov Avatar answered Sep 19 '22 10:09

Alexey Romanov