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)
...
当你只有一个可用的if
–else
结构时,很容易搞砸。
当然,在我一开始给出的简单示例中,使用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 语句和/或代码重复的混乱,有几种方法可以处理这种情况。
您可以使用 Option
或 Either
做各种偷偷摸摸的事情来保持状态流动(使用 orElse
和 fold
),这样您就可以只进行所需的计算。
您最好按照您的建议创建一个 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 语句实际上属于哪个闭包。这个问题通过明确要求def
—return*
对应来解决。
或者,需要在返回的语句周围设置警卫。 breakable
—break
但遗憾的是无法返回值。一些基于 continuation 的解决方案将能够实现该目标,但我想等待那里的一些普遍接受和库。
【讨论】:
以上是关于scala闭包/匿名函数中的多个返回点的主要内容,如果未能解决你的问题,请参考以下文章