Consider the following Scala case class:
case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
Pattern matching allows me to extract one field and discard others, like so:
someVal match {
case WideLoad(_, _, _, d, _) => d ! SomeMessage(...)
}
What I would like to do, and what's more relevant when a case class has ~20 odd fields, is to extract only a few values in a way that does not involve typing out WideLoad(_, _, _, _, _, some, _, _, _, thing, _, _, interesting)
.
I was hoping that named args could help here, although the following syntax doesn't work:
someVal match {
case WideLoad(d = dActor) => dActor ! SomeMessage(...)
// ^---------- does not compile
}
Is there any hope here, or am I stuck typing out many, many _, _, _, _
?
EDIT: I understand that I can do case wl @ WideLoad(...whatever...) => wl.d
, yet I'm still wondering whether there's even terser syntax that does what I need without having to introduce an extra val
.
A pattern match includes a sequence of alternatives, each starting with the keyword case. Each alternative includes a pattern and one or more expressions, which will be evaluated if the pattern matches. An arrow symbol => separates the pattern from the expressions.
Case classes help us use the power of inheritance to perform pattern matching. The case classes extend a common abstract class. The match expression then evaluates a reference of the abstract class against each pattern expressed by each case class.
Notes. Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.
It is defined in Scala's root class Any and therefore is available for all objects. 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. A symbol => is used to separate the pattern from the expressions.
I don't know if this is appropriate, but you can also build an object just to match that field, or that set of fields (untested code):
object WideLoadActorRef {
def unapply(wl: WideLoad): Option[ActorRef] = { Some(wl.d) }
}
someVal match {
case WideLoadActorRef(d) => d ! someMessage
}
or even
object WideLoadBnD {
def unapplySeq(wl: WideLoad): Option[(Int,ActorRef)] = { Some((wl.b,wl.d)) }
}
someVal match {
case WideLoadBnD(b, d) => d ! SomeMessage(b)
}
You can always fall back to guards. It's not really nice, but better than normal pattern matching for you monster case classes :-P
case class Foo(a:Int, b:Int, c:String, d:java.util.Date)
def f(foo:Foo) = foo match {
case fo:Foo if fo.c == "X" => println("found")
case _ => println("arrgh!")
}
f(Foo(1,2,"C",new java.util.Date())) //--> arrgh!
f(Foo(1,2,"X",new java.util.Date())) //--> found
That said I think you should rethink your design. Probably you can logically group some parameters together using case classes, tuples, lists, sets or maps. Scala does support nested pattern matching:
case class Bar(a: Int, b:String)
case class Baz(c:java.util.Date, d:String)
case class Foo(bar:Bar, baz:Baz)
def f(foo:Foo) = foo match {
case Foo(Bar(1,_),Baz(_,"X")) => println("found")
case _ => println("arrgh!")
}
f(Foo(Bar(1,"c"),Baz(new java.util.Date, "X"))) //--> found
f(Foo(Bar(1,"c"),Baz(new java.util.Date, "Y"))) //--> arrgh!
You can just specify the type in the matched pattern:
case class WideLoad(a: String, b: Int, c: Float, d: ActorRef, e: Date)
val someVal = WideLoad(...)
someVal match {
case w: WideLoad => w.d ! SomeMessage(...)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With