What is the difference between unapply and unapplySeq?
Without going into details and simplifying a bit:
For regular parameters apply
constructs and unapply
de-structures:
object S {
def apply(a: A):S = ... // makes a S from an A
def unapply(s: S): Option[A] = ... // retrieve the A from the S
}
val s = S(a)
s match { case S(a) => a }
For repeated parameters, apply
constructs and unapplySeq
de-structures:
object M {
def apply(a: A*): M = ......... // makes a M from an As.
def unapplySeq(m: M): Option[Seq[A]] = ... // retrieve the As from the M
}
val m = M(a1, a2, a3)
m match { case M(a1, a2, a3) => ... }
m match { case M(a, as @ _*) => ... }
Note that in that second case, repeated parameters are treated like a Seq
and the similarity between A*
and _*
.
So if you want to de-structure something that naturally contains various single values, use unapply
. If you want to de-structure something that contains a Seq
, use unapplySeq
.
Fixed-arity vs. variable arity. Pattern Matching in Scala (pdf) explains it well, with mirroring examples. I also have mirroring examples in this answer.
Briefly:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
scala> List(1,2,3,4) match { case Sorted(xs) => xs }
res0: Seq[Int] = List(1, 2, 3, 4)
scala> List(1,2,3,4) match { case SortedSeq(a, b, c, d) => List(a, b, c, d) }
res1: List[Int] = List(1, 2, 3, 4)
scala> List(1) match { case SortedSeq(a) => a }
res2: Int = 1
So, which do you think is exhibited in the following example?
scala> List(1) match { case List(x) => x }
res3: Int = 1