Why does Scala have both unapply
and unapplySeq
? What is the difference between the two? When should I prefer one over the other?
Whereas the apply method is like a constructor which takes arguments and creates an object, the unapply takes an object and tries to give back the arguments. This is most often used in pattern matching and partial functions. The apply method creates a CustomerID string from a name .
The unapply method breaks the arguments as specified and returns firstname object into an extractor . It returns a pair of strings if as an argument, the first name and last name is passed else returns none. Example : Scala.
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
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