免责声明:在有人说之前:是的,我知道这是不好的风格,不被鼓励。我这样做只是为了使用 Scala 并尝试了解更多关于类型推断系统如何工作以及如何调整控制流的信息。我不打算在实践中使用此代码。
所以:假设我在一个相当长的函数中,一开始有很多连续的检查,如果它们失败,都应该导致函数返回一些其他值(而不是抛出),否则返回正常值. 我不能return
在Function
. 但是我可以模拟吗?有点像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]
——这有点痛苦。有什么办法可以解决这个问题吗?