Как я могу реализовать ранний возврат извне тела метода в Scala?

Заявление об ограничении ответственности: Прежде, чем кто-то это скажет: да, я знаю, что это плохой стиль, а не поощряется. Я просто делаю это, чтобы поиграть со Scala и попытаться узнать больше о том, как работает система вывода типов и как настроить поток управления. Я не собираюсь использовать этот код на практике.


Итак: предположим, я нахожусь в довольно длинной функции, с множеством последовательных проверок в начале, которые, если они терпят неудачу, все должны вызвать функцию вернуть какое-то другое значение (не выбросить), а в противном случае вернуть нормальное значение. Я не могу использовать return в теле функции . Но можно ли это смоделировать? Немного похоже на break , смоделированный в scala.util.control.Breaks ?

Я придумал следующее:

object TestMain {

  case class EarlyReturnThrowable[T](val thrower: EarlyReturn[T], val value: T) extends ControlThrowable
  class EarlyReturn[T] {
    def earlyReturn(value: T): Nothing = throw new EarlyReturnThrowable[T](this, value)
  }

  def withEarlyReturn[U](work: EarlyReturn[U] => U): U = {
    val myThrower = new EarlyReturn[U]
    try work(myThrower)
    catch {
      case EarlyReturnThrowable(`myThrower`, value) => value.asInstanceOf[U]
    }
  }

  def main(args: Array[String]) {
    val g = withEarlyReturn[Int] { block =>
      if (!someCondition)
        block.earlyReturn(4)

      val foo = precomputeSomething
      if (!someOtherCondition(foo))
        block.earlyReturn(5)

      val bar = normalize(foo)
      if (!checkBar(bar))
        block.earlyReturn(6)

      val baz = bazify(bar)
      if (!baz.isOK)
        block.earlyReturn(7)

      // now the actual, interesting part of the computation happens here
      // and I would like to keep it non-nested as it is here
      foo + bar + baz + 42 // just a dummy here, but in practice this is longer
    }
    println(g)
  }
}

Мои проверки здесь явно фиктивные, но основная Дело в том, что я бы хотел избежать чего-то вроде этого, когда действительно интересный код оказывается слишком вложенным, на мой вкус:

if (!someCondition) 4 else {
  val foo = precomputeSomething
  if (!someOtherCondition(foo)) 5 else {
    val bar = normalize(foo)
    if (!checkBar(bar)) 6 else {
      val baz = bazify(bar)
      if (!baz.isOK) 7 else {
        // actual computation
        foo + bar + baz + 42 
      }
    }
  }
}

Мое решение здесь отлично работает, и я могу вернуться раньше с 4 в качестве возвращаемого значения, если я хочу . Проблема в том, что у меня есть , чтобы явно написать параметр типа [Int] , что немного затруднительно. Есть ли способ обойти это?

7
задан Jean-Philippe Pellet 8 July 2011 в 20:19
поделиться