mogli
mogli

Reputation: 1609

How to pattern match on Map?

val paths @ Array(key_dc_outputDirectory, key_dc_path) = Array("DC_BIN", "DC_PATH")

but below gives a compiler error:

val map @ Map(p1, p2) = Map("key1" -> "value1", "key2" -> "value2")

value Map is not a case class, nor does it have an unapply/unapplySeq member

What is the correct syntax to avoid the error?

Upvotes: 1

Views: 1754

Answers (1)

yǝsʞǝla
yǝsʞǝla

Reputation: 16412

The problem obviously is that Map does not have unapplySeq method. It might not have lots of sense to have it because you would not know in which order you would get your elements.

Anyhow, the closest I could get to is this:

scala> object MapOops {
     |   def apply[K,V](ps: (K,V)*): Map[K,V] =
     |     ps.toMap
     |
     |   def unapplySeq[K,V](m: Map[K,V]): Option[Seq[(K,V)]] =
     |     if(m.isEmpty) None else Some(m.toSeq)
     | }
defined object MapOops

scala> val map@MapOops(p1, p2) = MapOops(1 -> "one", 2 -> "two")
map: Map[Int,String] = Map(1 -> one, 2 -> two)
p1: (Int, String) = (1,one)
p2: (Int, String) = (2,two)

or, even shorter:

scala> val map@MapOops(p1, p2) = Map(1 -> "one", 2 -> "two")
map: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
p1: (Int, String) = (1,one)
p2: (Int, String) = (2,two)

It does not make sense to pimp Map with something like this:

implicit class MapOops[K,V](val m: Map[K,V]) extends AnyVal

Because when you use Map in pattern matching no implicit conversion could happen since MapOops type is not requested/implied.

For example: case Map(...) or val Map(...) would require type Map, not MapOops so implicit conversion will not take place and unapplySeq method will not be found. And if you use MapOops explicitly, then no implicit conversion is necessary.

If you use this pattern a lot then you might find this helper class useful, otherwise a more sensible solution is to have an extra conversion as in @jwvh's answer.

Upvotes: 2

Related Questions