Экстракторы:
Есть два метода, используемые для экстракторов, unapply
и unapplySeq
. Они используются в нескольких назначениях переменных и сопоставлении шаблонов.
Первый случай использования, где исключить его принимает объект он должен соответствовать и возвращает Boolean
в зависимости от того или не соответствует его, например,
trait Gender
trait Male extends Gender
trait Female extends Gender
object Male extends Male
object Female extends Female
class Person(val g: Gender, val age: Int)
object Adult {
def unapply(p: Person) = p.age >= 18
}
def check(p: Person) = p match {
case Adult() => println("An Adult")
case _ => println("A Child")
}
//Will print: An Adult since Adult.unapply returns true.
check(new Person(Female, 18))
//Will print: A Child as it falls through to the _ case.
check(new Person(Male, 17))
Честно говоря, я на самом деле не получают цели вышеупомянутого синтаксиса, так как это можно сделать почти так же просто, просто поместив код в операторы case
. Конечно, если у вас есть лучший пример, оставьте комментарий ниже
Общий случаем, когда unapply
занимает некоторое фиксированное число параметров и возвращает либо Option[T]
для одного параметра или Option[(p1,p2,...)]
для нескольких, т.е. Кортеж с соответствием значений, например, продолжив из кода выше:
object Person {
def apply(g: Gender, age: Int) = new Person(g, age)
def unapply(p: Person) = if(p.age < 0) None else Some((p.g, p.age))
}
//Using Person.apply as described in the Basics section
val alice = Person(Female, 30)
val bob = Person(Male, 25)
//This calls Person.unapply(alice), which returns Some((Female, 30)).
//alice_gender is assigned Female and alice_age 30.
val Person(alice_gender, alice_age) = alice
bob match {
//Calls Person.unapply(bob), but sees that g is Male, so no match.
case Person(Female, _) => println("Hello ma'am")
//Calls Person.unapply(bob) and assigns age = bob.age, but it doesn't pass
//the 'if' statement, so it doesn't match here either.
case Person(Male, age) if age < 18 => println("Hey dude")
//So bob falls through to here
case _ => println("Hello Sir")
}
Person(Male,-1) match {
//Person.unapply(Person.apply(Male,-1)) returns None because p.age < 0.
//Therefore this case will not match.
case Person(_, _) => println("Hello person")
//Thus it falls through to here.
case _ => println("Are you Human?")
}
Примечание:Case classes делать все те apply
/unapply
(как и другие материалы), поэтому используйте их, когда это возможно, чтобы сэкономить время и уменьшить код.
unapplySeq
. Это работает аналогично unapply
, как указано выше, за исключением того, что он должен возвращать Option
какой-либо последовательности.
Как простой пример,
scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
Больше TODO: кортежи, символы, XML-литералы. – missingfaktor
Я не думаю, что XML подходит, потому что его не по-настоящему сахара в смысле сокращения чего-то еще. Однако я согласен с кортежами и символами. –
Если вы видели, что код выполнен для создания экземпляров XML DOM, соответствующих XML-литералам, я думаю, вы должны согласиться с тем, что литералы являются аббревиатурой! –