responsabilidad: Antes de que alguien dice: sí, ya sé que es malo estilo y no se anima. Solo estoy haciendo esto para jugar con Scala y tratar de aprender más sobre cómo funciona el sistema de inferencia de tipo y cómo modificar el flujo de control. No pretendo usar este código en la práctica.¿Cómo podría implementar una devolución anticipada desde fuera del cuerpo de un método en Scala?
Así: supongo que estoy en una función más bien largo, con una gran cantidad de comprobaciones sucesivas al principio, que, si no, se supone que todos debemos hacer que la función para devolver algún otro valor (no tirar) , y devuelve el valor normal. No puedo usar return
en el cuerpo de Function
. ¿Pero puedo simularlo? Un poco como break
se simula en scala.util.control.Breaks
?
he llegado con esto:
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)
}
}
Mis cheques aquí son obviamente ficticia, pero el punto principal es que me gustaría evitar algo así, donde el código realmente interesante termina siendo manera anidado demasiado para mi gusto:
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
}
}
}
}
mi solución funciona bien aquí, y puedo regresar temprano con 4 como valor de retorno si quiero. El problema es que tengo escribir explícitamente el parámetro de tipo [Int]
- que es un poco de dolor. ¿Hay alguna forma de evitar esto?
No creo que sea _hasta_ una mala práctica. Parece que se usa en exceso en los idiomas que lo hacen fácil y no ofrecen buenas alternativas. –
Si escribe la distinción entre mayúsculas y minúsculas (utilizando 'else if'), su" cálculo real "solo se anida una vez en comparación con su jerarquía no anidada. ¿Cuál es el problema con eso? En su ejemplo, todo lo que guarda es una palabra clave 'else', pero tiene todos los gastos generales. – Raphael
@Raphael Sí * * en ese ejemplo, pero he especificó que estoy mirando a los casos en que, por supuesto, que tengo más de una condición para comprobar - por lo general 3 o 4, por lo que mi código real se anida 3 o 4 veces. –