Reputation: 19478
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
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