Давайте сделаем это из кода.Сначала небольшая перезапись:
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"
}
Новая перезапись означает точно так же, как .Строка комментария использует инфиксную нотацию для экстракторов, а вторая использует нормальную нотацию.Они оба переводят в одно и то же.
Итак, Scala будет многократно подавать «Джули» в экстрактор, пока все несвязанные переменные не будут присвоены Some
.Первый экстрактор - &
, поэтому мы получаем это:
&.unapply("Julie") == Some(("Julie", "Julie"))
Мы вернули Some
, поэтому мы можем продолжить матч.Теперь у нас есть кортеж из двух элементов, и у нас также есть два экстрактора внутри &
, поэтому мы передаем каждый элемент кортежа каждому экстрактору:
Brothers.unapply("Julie") == ?
Sisters.unapply("Julie") == ?
Если оба из них возвращают Some
вещь, то матч будет успешным.Ради интереса давайте перепишем этот код без сопоставления с образцом:
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"
}
Уродливый код, даже без оптимизации, чтобы получить extractor12
только если extractor11
не пусто, и без повторения кода, которыйпошел туда, где есть комментарий.Поэтому я напишу это в еще одном стиле:
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"
}
}
Шаблон flatMap
/ map
в начале предлагает еще один способ написания этого:
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"
)
Вы должны быть в состоянии запустить весь этот код и увидеть результаты для себя.