Является ли дизайн PartialFunction неэффективным?

Это то, что я задумался некоторое время. Я часто вижу этот шаблон:

if (pf.isDefinedAt(in)) pf(in)

Если разбить его на два отдельных вызова, все шаблоны, которые оценивались в #isDefinedAt, затем также оцениваются в #apply. Например:

object Ex1 {
  def unapply(in: Int) : Option[String] = {
    println("Ex1")
    if (in == 1) Some("1") else None
  }
}

object Ex2 {
  def unapply(in: Int) : Option[String] = {
    println("Ex2")
    if (in == 2) Some("2") else None
  }
}

val pf : PartialFunction[Int,String] = {
  case Ex1(result) => result
  case Ex2(result) => result
}

val in = 2

if (pf.isDefinedAt(in)) pf(in)

Что печатает

Ex1
Ex2
Ex1
Ex2
res52: Any = 2

В худшем случае, когда ваш шаблон соответствует последнему, вы дважды оценили свои шаблоны / экстракторы при вызове PartialFunction. Это может стать неэффективным при сопоставлении с пользовательскими экстракторами, которые выполняли больше, чем просто сопоставление с простым классом или шаблоном списка (например, если у вас был экстрактор, который анализировал XML-документ и возвращал некоторые объекты значений).

PartialFunction # lift страдает от та же двойная оценка:

scala> pf.lift(2)
Ex1
Ex2
Ex1
Ex2
res55: Option[String] = Some(2)

Есть ли способ условно вызвать функцию, если она определена без потенциального вызова всех ваших экстракторов дважды?

13
задан Collin 31 October 2010 в 20:00
поделиться