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

Posted

技术标签:

【中文标题】scala闭包/匿名函数中的多个返回点【英文标题】:Multiple return points in scala closure/anonymous function 【发布时间】:2011-02-23 08:12:57 【问题描述】:

据我了解,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)
...

当你只有一个可用的ifelse 结构时,很容易搞砸。

当然,在我一开始给出的简单示例中,使用else 会更容易。抱歉,我以为这很清楚。

【问题讨论】:

使用 else 语句有什么问题? 在您给出的示例中,完全没有理由避免使用 else 关键字;如果您使用else,则不会计算额外的表达式,因此在此处使用提前返回将一无所获。 对不起,我修改了。认为很明显doMoreStuff 部分实际上做了更多。 【参考方案1】:

如果您的匿名函数如此复杂,我会使其更加明确。匿名函数不适合比几行更复杂的事情。您可以通过在 using 方法中声明它来使其成为私有方法

def myF(i:Int):Int = 
    if (i%2 == 0) return i
    doMoreStuffAndReturnSomething(i)

someList.map(myF(_))

这是您的变通方法的一种变体,但更简洁。它们都将其保持为本地方法范围的私有。

【讨论】:

这是一个很好的解决方法。我是 scala newb,所以我真的不明白为什么需要这样做,但它解决了问题。【参考方案2】:

在您的代码注释中,您写道要避免使用 else 关键字,但恕我直言,这正是您想要的,甚至更短了两个字符 ;-)

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

【讨论】:

实际上,我会说它节省了两个以上的字符:显式的return 无论如何都会强制您声明返回类型……但是我的实际用例会比示例复杂一些我本来给的,所以不只是为了保存角色。【参考方案3】:

您给出的示例很容易通过 if 语句解决。这样做不会造成任何性能或其他处罚。

但你可能还有一些其他的情况,大概是这样的

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

bigComputation()

如果您想避免将其转换为不带返回的表单所需的 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())

就个人而言,我不认为它更清晰(当然也不会更快),但这是可能的。

【讨论】:

是的,它与没有返回的原始示例一样复杂(或者甚至更复杂)。但在其他情况下,这当然是一种有效的方法。【参考方案4】:

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

或者,需要在返回的语句周围设置警卫。 breakablebreak 但遗憾的是无法返回值。一些基于 continuation 的解决方案将能够实现该目标,但我想等待那里的一些普遍接受和库。

【讨论】:

以上是关于scala闭包/匿名函数中的多个返回点的主要内容,如果未能解决你的问题,请参考以下文章

scala高级特性-01

Scala基础:作为值的函数及匿名函数柯里化闭包及控制抽象

python函数:匿名函数,闭包,装饰器

JavaScript——匿名函数和闭包

高阶函数返回函数闭包匿名函数装饰器偏函数

Scala编程之闭包(closure)