scala - parameter - ¿Cuál es la diferencia entre unapply y unapplySeq?
scala generic (2)
¿Por qué Scala tiene tanto una unapply
como una unapplySeq
? ¿Cuál es la diferencia entre los dos? ¿Cuándo debería preferir uno sobre el otro?
Arity fijo vs. arity variable. Pattern Matching en Scala (pdf) lo explica bien, con ejemplos de duplicación. También tengo ejemplos de reflejo en esta respuesta .
Brevemente:
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
Entonces, ¿cuál crees que se exhibe en el siguiente ejemplo?
scala> List(1) match { case List(x) => x }
res3: Int = 1
Sin entrar en detalles y simplificar un poco:
Para los parámetros regulares, apply
constructs y unapply
estructuras.
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 }
Para los parámetros repetidos, apply
constructs y unapplySeq
las estructuras de unapplySeq
:
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 @ _*) => ... }
Tenga en cuenta que en ese segundo caso, los parámetros repetidos se tratan como un Seq
y la similitud entre A*
y _*
.
Por lo tanto, si desea unapply
algo que, naturalmente, contiene varios valores individuales, use "no unapply
. Si desea unapplySeq
algo que contiene un Seq
, use unapplySeq
.