schmmd
schmmd

Reputation: 19478

How does scala match on Arrays?

looking through the Scala code, the convenient array creation syntax is achieved by adding an apply method to object Array. At first, I thought this was achieved somehow through case classes because you can run the following, but this does not seem to be the case:

Array(1,2,3) match { case Array(a, b, c) => a + b + c }

I know that I also need to look at WrappedArray and all the superclasses, but I can't figure out how scala achieves this matching on Arrays (and I need to become more familiar with the scala collections class hierarchy). It certainly doesn't work with a run-of-the-mill class.

scala>  class A(val x: Int)
scala>  new A(4) match { case A(x) => x }
<console>:9: error: not found: value A
              new A(4) match { case A(x) => x }
                                    ^
<console>:9: error: not found: value x
              new A(4) match { case A(x) => x }

How do they get this to work with Array?

Upvotes: 1

Views: 1771

Answers (1)

Luigi Plinge
Luigi Plinge

Reputation: 51109

You can pattern match with this syntax on any class so long as you have an object with with an unapply or unapplySeq (in the case of varargs) method that returns an Option or Boolean. These are known as extractors. The lines in question from object Array are

  def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
    if (x == null) None else Some(x.toIndexedSeq) 

In your example you can get it to match using

class A(val x: Int)

object A {
  def unapply(a: A) = Some(a.x)
}

so now

scala> new A(4) match { case A(x) => x }
res1: Int = 4

The Programming In Scala chapter on extractors may be useful.

For case classes, an unapply method is just one of the methods that is included for free, along with toString, equals, etc.

Note that the extractor doesn't have to have the same name as the class in question, and it doesn't have to be defined within an object object. For example, in your case you could equally write

val xyz = new { def unapply(a: A) = Some(a.x) } //extending java.lang.Object

new A(4) match { case xyz(x) => x }             //Int = 4

Upvotes: 5

Related Questions