scala闭包/匿名函数中的多个返回点

时间:2010-05-24 17:27:06

标签: scala closures return-value anonymous-function

据我所知,Scala无法在匿名函数中有多个返回点,即

someList.map((i) => {
    if (i%2 == 0) return i // the early return allows me to avoid the else clause
    doMoreStuffAndReturnSomething(i) // thing of this being a few more ifs and returns
})

提出error: return outside method definition。 (如果没有提出这个问题,那么代码将不起作用,因为我希望它可以工作。)

我可以解决的一个解决方法是以下

someList.map({
    def f(i: Int):Int = {
        if (i%2 == 0) return i
        doMoreStuffAndReturnSomething(i)
    }
    f
})
但是,我想知道是否还有另一种“接受”的做法。也许有可能没有内部功能的名称?

(用例是在循环中模拟一些有价值的continue构造。)

修改

请相信我,有必要避免使用else语句,因为doMoreStuff部分可能看起来像:

val j = someCalculation(i)
if (j == 0) return 8
val k = needForRecalculation(i)
if (k == j) return 9
finalRecalc(i)
...

当您只有if - else结构时,很容易搞砸了。

当然,在我刚开始提供的简单示例中,使用else更容易。对不起,我觉得这很清楚。

4 个答案:

答案 0 :(得分:5)

如果您的匿名函数那么复杂,我会让它更明确。匿名函数不适用于比几行更复杂的东西。您可以通过在using方法

中声明它来使其成为私有方法
def myF(i:Int):Int = {
    if (i%2 == 0) return i
    doMoreStuffAndReturnSomething(i)
}
someList.map(myF(_))

这是您的变通方法的变体,但更清洁。它们都将其保密为本地方法范围。

答案 1 :(得分:3)

在你的代码评论中,你写道你要避免使用else关键字,但恕我直言这完全符合你的要求,甚至两个字符更短; - )

someList.map((i) => {
    if (i%2 == 0) i else
    doMoreStuffAndReturnSomething(i)
})

答案 2 :(得分:3)

您给出的示例很容易通过if语句解决。这样做没有任何表现或其他惩罚。

但是你可能还有其他情况,看起来大致像

if (test) {
  if (anotherTest) {
    val a = someComputation()
    if (testOf(a)) return otherComputation()
  }
  else if (yetAnotherTest) return whatever()
}
bigComputation()

如果你想避免将if转换为没有返回的表单所需的if语句和/或代码重复的纠结,有几种方法可以解决这种情况。

您可以使用OptionEither进行各种偷偷摸摸的事情以保持状态流动(使用orElsefold),这样您只需进行计算需要。

你最好按照你的建议创建一个def。但只是为了比较,考虑一种Option-wrapping风格:

i => {
  ( if ((i%2)==0) Some(i) 
    else None
  ).getOrElse(doStuffAndReturn(i))
}

在上面的大例子中,这种风格会给出

( if (test) {
    if (anotherTest) {
      val a = someComputation()
      if (testOf(a)) Some(otherComputation()) else None
    }
    else if (yetAnotherTest) Some(whatever())
    else None
}).getOrElse(bigComputation())

就个人而言,我认为它更清晰(并且肯定不会更快),但它是可能的。

答案 3 :(得分:1)

我认为匿名函数中返回点的主要问题是匿名函数可能会出现在人们通常不会想到它的地方。因此,不清楚返回语句实际上属于哪个闭包。通过明确要求def - return*对应来解决此问题。

或者,人们需要围绕要返回的声明的警卫。 breakable - break但遗憾的是无法返回值。一些基于延续的解决方案将能够实现这一目标,但我想等待那里的一些普遍接受和库。