简体   繁体   English

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

[英]Multiple return points in scala closure/anonymous function

As far as I understand it, there is no way in Scala to have multiple return points in an anonymous function, ie 据我所知,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
})

raises an error: return outside method definition . 引发error: return outside method definition (And if it weren't to raise that, the code would not work as I'd like it to work.) (如果没有提出这个问题,那么代码将不起作用,因为我希望它可以工作。)

One workaround I could thing of would be the following 我可以做的一个解决方法是以下

someList.map({
    def f(i: Int):Int = {
        if (i%2 == 0) return i
        doMoreStuffAndReturnSomething(i)
    }
    f
})

however, I'd like to know if there is another 'accepted' way of doing this. 但是,我想知道是否还有另一种“接受”的做法。 Maybe a possibility to go without a name for the inner function? 也许有可能没有内部功能的名称?

(A use case would be to emulate some valued continue construct inside the loop.) (一个用例是在循环中模拟一些有价值的continue构造。)

Edit 编辑

Please believe me, that there is a need for avoiding the else statement, because, the doMoreStuff part might actually look like: 请相信我,需要避免使用else语句,因为doMoreStuff部分可能看起来像:

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

which, when you only have an ifelse structure available gets easily messed up. 当你只有if - else结构时,很容易搞砸了。

Of course, in the simple example I gave in the beginning, it is easier to just use else . 当然,在我开头给出的简单示例中,使用else更容易。 Sorry, I thought this was clear. 对不起,我觉得这很清楚。

If your anonymous function's that complex, I'd make it more explicit. 如果你的匿名函数那么复杂,我会更清楚。 Anonymous functions are not suited to anything more complex than a few lines. 匿名函数不适用于比几行更复杂的东西。 You could make it method private by declaring it within the using method 您可以通过在using方法中声明它来使其成为私有方法

def myF(i:Int):Int = {
    if (i%2 == 0) return i
    doMoreStuffAndReturnSomething(i)
}
someList.map(myF(_))

This is a variation on your workaround, but is cleaner. 这是您的变通方法的变体,但更清洁。 They both keep it private to the local method scope. 它们都将其保密为本地方法范围。

In your code comment, you wrote that you want to avoid the else keyword, but IMHO this does exactly what you want and its even two characters shorter ;-) 在您的代码注释中,您写道您要避免使用else关键字,但是恕我直言这完全符合您的要求,甚至两个字符更短;-)

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

The example you've given is easily solved by an if statement. 您给出的示例很容易通过if语句解决。 There are no performance or other penalties for doing this. 这样做没有表现或其他处罚。

But you might have some other situation, which looks roughly like 但是你可能还有其他一些情况,看起来很像

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

There are a few ways to deal with this sort of situation if you want to avoid the tangle of if-statements and/or code duplication needed to convert this to a form without returns. 如果你想避免将if转换为没有返回的表单所需的if语句和/或代码重复的混乱,有几种方法可以处理这种情况。

There are various sneaky things you can do with Option or Either to keep state flowing along (with orElse and fold ) so that you do only the computations you need to. 有各种各样的偷偷摸摸的事情可以做OptionEither保持状态一起流动(与orElsefold ),这样你只能做的计算需要。

You're really better off creating a def as you suggest. 你建议你最好创建一个def。 But just to compare, consider an Option-wrapping style: 但只是为了比较,考虑一种Option-wrapping风格:

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

On the large example above, this style would give 在上面的大例子中,这种风格会给出

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

Personally, I don't think it's clearer (and it's certainly not faster), but it is possible. 就个人而言,我认为它更清晰(并且肯定不会更快),但它是可能的。

I think the main problem with return points in anonymous functions is that an anonymous function might spring up at a place where one normally wouldn't expect it. 我认为匿名函数中返回点的主要问题是匿名函数可能会出现在人们通常不会期望它的地方。 So, it wouldn't be clear which closure the return statement would actually belong to. 因此,不清楚返回语句实际上属于哪个闭包。 This problem is solved by explicitly requiring a defreturn* correspondance. 通过明确要求def - return*对应来解决这个问题。

Alternatively, one would need guards around the statement from which to return. 或者,人们需要围绕要返回的声明的警卫。 breakablebreak but unfortunately can't return a value with that. breakable - break但遗憾的是无法返回值。 Some continuation based solutions would be able to reach that goal, though I'd like to wait for some general acceptance and libraries there. 一些基于延续的解决方案将能够实现这一目标,尽管我想等待一些普遍的接受和库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM