免責事項:誰かがそれを言う前に: はい、私はそれが悪いスタイルであり、奨励されていないことを知っています. これは、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]
ことです — これは少し面倒です。これを回避する方法はありますか?