Os extratores parecem nada mais do que içados e embrulhados PartialFunction
:
type ?=>[A, B] = PartialFunction[A, B]
trait Extractor[A, B] { def unapply(x: A): Option[B] }
def Extractor[A, B](fn: A ?=> B) = new Extractor[A, B] {
def unapply(x: A): Option[B] = fn.lift(x)
}
Vamos usar essa estrutura em alguns dados:
val people = List(
Person("Bradley", "Smith"),
Person("Paul", "Freeman", Some(Position("Programmer"))),
Person("Mary", "Martyr", Some(Position("Manager", Some(Company("IBM", Some(1881)))))))
Agora temos a opção de definir um extrator para obter a empresa em que a pessoa trabalha, se houver, ou, em vez disso, começar com uma função mais básica; vamos ao básico primeiro:
val getCompany: Person ?=> Company = {
case Person(_, _, Some(Position(_, Some(c)))) => c
}
Teríamos que usar uma sintaxe mais longa aqui se, em vez de getCompany
, tivéssemos definido um extrator completo imediatamente:
val companies = people.collect(getCompany).distinct
Agora podemos converter getCompany
em um extrator chamado EmployedAt
para maior conveniência de correspondência de padrões:
val EmployedAt = Extractor(getCompany)
Os extratores compõem melhor em consultas de correspondência de padrões mais complexas:
def getEmployees(company: Company) =
people.collect { case p @ EmployedAt(`company`) => p }