更简洁的Scala提取器定义语法

时间:2014-06-18 18:27:58

标签: scala pattern-matching

提取器可以是减少模式匹配代码重复的一种非常有用的方法,但是,它们中包含的逻辑通常只是一个简单的单行模式,需要从代码中删除,例如,我有一个Person(_, _, Some(Position(_, Some(company))))的重复模式,所以我提出了这个提取器:

object EmployedAt {
  def unapply(x: Person): Option[Company] = x match {
    case Person(_, _, Some(Position(_, company))) => company
    case _ => None
  }
}

我可以这样使用:

val companies = people.collect { case EmployedAt(c) => c }.distinct

def numEmployees(company: Company) =
  people.collect { case EmployedAt(`company`) => }.size

people.collect { case p @ EmployedAt(c) if numEmployees(c) >= 2 => (p, c) }

等 - 所有非常好,简洁和可读......除了提取器实现本身。我看到的问题是,最终,提取器只归结为第一个case语句,其余的只是样板。相反,我认为以下更适合定义简单(可能是一次性或两次性)提取器:

def EmployedAt(x: Person): Company = {
  case Person(_, _, Some(Position(_, Some(company)))) => company
}

...这是2条实线而不是4条。

- 我如何继续阅读样板来达到上述简洁的目的?

1 个答案:

答案 0 :(得分:4)

我立即开始使用潜在的解决方案,我认为我已经找到了一个非常好的解决方案,除了允许在没有object + unapply +的情况下定义提取器Option[T] + case _ => None样板,也让读者立即明白给定函数是一个提取器,并将其静态标记为Extractor

trait Extractor[T, U] { def unapply(x: T): Option[U] }
object Extractor {
  def apply[T, U](f: PartialFunction[T, U]) = new Extractor[T, U] {
    def unapply(x: T) = f.lift(x)
  }
}

val EmployedAt = Extractor[Person, Company] {
  case Person(_, _, Some(Position(_, Some(company)))) => company
}

我没有打算立即回答我自己的问题,但结果却是如此。我仍然对可能更有能力的Scala社区成员的批评和其他建议持开放态度! :)