Hagamos esto desde el código. En primer lugar, una pequeña reescritura:
object & { def unapply[A](a: A) = Some(a, a) }
"Julie" match {
// case Brothers(_) & Sisters(_) => "Julie has both brother(s) and sister(s)"
case &(Brothers(_), Sisters(_)) => "Julie has both brother(s) and sister(s)"
case Siblings(_) => "Julie's siblings are all the same sex"
case _ => "Julie has no siblings"
}
La nueva reescritura significa exactamente lo mismo. La línea de comentario usa notación infija para extractores, y la segunda usa notación normal. Ambos se traducen en lo mismo.
Por lo tanto, Scala alimentará "Julie" al extractor, repetidamente, hasta que todas las variables no vinculadas se hayan asignado al objeto Some
. El primer extractor es &
, así que conseguir esto:
&.unapply("Julie") == Some(("Julie", "Julie"))
Llegamos Some
atrás, por lo que podemos proceder con el partido. Ahora tenemos una tupla de dos elementos, y tenemos dos extractores dentro &
, así que vamos a alimentar cada elemento de la tupla a cada extractora:
Brothers.unapply("Julie") == ?
Sisters.unapply("Julie") == ?
Si ambos regresan Some
cosa, entonces el partido se exitoso Sólo por diversión, vamos a volver a escribir el código sin la coincidencia de modelos:
val pattern = "Julie"
val extractor1 = &.unapply(pattern)
if (extractor1.nonEmpty && extractor1.get.isInstanceOf[Tuple2]) {
val extractor11 = Brothers.unapply(extractor1.get._1)
val extractor12 = Sisters.unapply(extractor1.get._2)
if (extractor11.nonEmpty && extractor12.nonEmpty) {
"Julie has both brother(s) and sister(s)"
} else {
"Test Siblings and default case, but I'll skip it here to avoid repetition"
}
} else {
val extractor2 = Siblings.unapply(pattern)
if (extractor2.nonEmpty) {
"Julie's siblings are all the same sex"
} else {
"Julie has no siblings"
}
código de feo aspecto, incluso sin la optimización para conseguir solamente extractor12
si extractor11
no está vacío, y sin la repetición de código que debería haber ido donde hay un comentario . Así que voy a escribir en otro estilo:
val pattern = "Julie"
& unapply pattern filter (_.isInstanceOf[Tuple2]) flatMap { pattern1 =>
Brothers unapply pattern1._1 flatMap { _ =>
Sisters unapply pattern1._2 flatMap { _ =>
"Julie has both brother(s) and sister(s)"
}
}
} getOrElse {
Siblings unapply pattern map { _ =>
"Julie's siblings are all the same sex"
} getOrElse {
"Julie has no siblings"
}
}
El patrón de flatMap
/map
al principio sugiere otra manera de escribir esto:
val pattern = "Julie"
(
for {
pattern1 <- & unapply pattern
if pattern1.isInstanceOf[Tuple2]
_ <- Brothers unapply pattern1._1
_ <- Sisters unapply pattern1._2
} yield "Julie has both brother(s) and sister(s)
) getOrElse (
for {
_ <- Siblings unapply pattern
} yield "Julie's siblings are all the same sex"
) getOrElse (
"julie has no siblings"
)
usted debería ser capaz de ejecutar todo esto codificar y ver los resultados por ti mismo.
Vea también: http://stackoverflow.com/questions/2261358/pattern-matching-with-conjunctions-patterna-and-patternb – retronym