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

发布于 2024-09-03 10:27:58 字数 990 浏览 4 评论 0原文

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

引发错误:返回方法定义之外。 (如果不提出这个问题,代码将无法像我希望的那样工作。)

我可以采取的一种解决方法如下

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 会更容易。抱歉,我以为这已经很清楚了。

As far as I understand it, there is no way in Scala to have multiple return points in an anonymous function, i.e.

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. (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.)

Edit

Please believe me, that there is a need for avoiding the else statement, because, the doMoreStuff part might actually look like:

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.

Of course, in the simple example I gave in the beginning, it is easier to just use else. Sorry, I thought this was clear.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鲜血染红嫁衣 2024-09-10 10:27:58

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

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

这是您的解决方法的变体,但更干净。它们都将其保留在本地方法范围内。

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

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.

少钕鈤記 2024-09-10 10:27:58

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

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

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 ;-)

someList.map((i) => {
    if (i%2 == 0) i else
    doMoreStuffAndReturnSomething(i)
})
强辩 2024-09-10 10:27:58

您给出的示例可以通过 if 语句轻松解决。这样做不会产生绩效或其他处罚。

但是您可能会遇到其他情况,大致类似于

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

如果您想避免将其转换为不带返回的形式所需的 if 语句和/或代码重复的混乱,那么有几种方法可以处理这种情况。

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

你最好按照你的建议创建一个 def 。但为了进行比较,请考虑选项包装样式:

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())

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

The example you've given is easily solved by an if statement. 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.

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.

You're really better off creating a def as you suggest. But just to compare, consider an Option-wrapping style:

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.

玩套路吗 2024-09-10 10:27:58

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

或者,需要在要返回的语句周围有警卫。 breakablebreak 但遗憾的是无法返回值。一些基于延续的解决方案将能够实现该目标,尽管我想等待一些普遍接受和图书馆。

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.

Alternatively, one would need guards around the statement from which to return. breakablebreak but unfortunately can’t return a value with that. Some continuation based solutions would be able to reach that goal, though I’d like to wait for some general acceptance and libraries there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文