10

我和我的同事对以下代码的行为感到有些困惑。

def a: String = {
  None.foreach(return "1")
  return "2"
}

def b: String = {
  None.foreach(x => return "1")
  return "2"
}

正如预期的那样,调用b确实返回“2”。但是,调用a返回“1”。什么return "1"时候a被执行?

4

5 回答 5

11

形式的所有*功能评估

f({code})

相当于

val temp = { code }
f(temp)

所以,在第一种情况下,

val temp = return "1"
None.foreach(temp)   // Never reach this point!

而在二中,

val temp = (x: Nothing) => return 1
  // Equivalent: new Function1[Nothing,String]{ def apply(x: Nothing) = return "1" }
None.foreach(temp)   // Never call that weird function!

所以一切都好。

但是,等等,foreach需要一个A => Unit. return "1"这样的功能如何?好吧,Scala 从最具体的类型开始(Nothing,它是任何东西的子类,因此承诺做任何你要求它做的事情,除非它不存在)。而且,由于该语句不产生任何值(控制通过返回转义),它永远不会从Nothing. 所以,确实Nothing是 的子类Function1[A,Unit]

为了Nothing产生它——好吧,假装产生它——你实际上运行代码,然后返回。

*实际上,如果参数是按名称传递的,它会被偷偷转换() => { Code }并传入而不进行评估。

于 2012-11-30T21:22:32.447 回答
2

其他人已经解释了这种行为,但最好不要使用return

我会写类似的东西。

def b: String = {
  None.map(x => "1").getOrElse("2")
}

或者,如果我想返回第一个匹配的项目,List我会使用它。collectFirst

编辑:我看到问题被标记为functional programming. return如果尝试以功能样式进行编程,则应避免使用。以 A => B 的地图为例。如果您使用return,则会破坏该类型签名。

def a: String = { 
  val a = Option(5).map(x => if(x==6) return "aa" else 6); // isnt returning a `B` when x == 5.
  a.toString
};
于 2012-11-30T21:23:12.423 回答
1

Scala 使用急切的应用顺序评估。这意味着在替换函数的参数之前对参数进行评估。此外,值得回顾的是,函数对自己进行评估。它是函数应用程序,它计算函数的返回值。现在让我们看看每个参数的计算结果。

scala> :t () => "1"
() => java.lang.String

所以,在第二种情况下,我们得到了一个函数。它在通过之前被评估(对自身),但从未应用,因为None没有元素。不过,return "1"不需要申请。它只需要被评估,它具有重定向控制的副作用,然后从包含它的函数返回“1”。

于 2012-11-30T22:15:30.997 回答
1

这真的很酷——我不知道。查看http://www.scala-lang.org/docu/files/ScalaReference.pdf的第 91 页的语言参考:

return 表达式 return e必须出现在一些封闭的命名方法或函数的主体内。源程序中最内层的命名方法或函数f必须具有显式声明的结果类型,并且e的类型 必须符合它。return 表达式计算表达式 e 并将其值作为f的结果返回。

...

编译器生成的作为匿名函数扩展的apply方法在源程序中不算作命名函数,因此绝不是返回表达式的目标。

从嵌套匿名函数返回是通过抛出和捕获一个scala.runtime.NonLocalReturnException. 返回点和封闭方法之间的任何异常捕获都可能会看到异常。关键比较确保这些异常仅被返回终止的方法实例捕获。

如果 return 表达式本身是匿名函数的一部分,则f的封闭实例可能在 return 表达式执行之前已经返回。在这种情况下,抛出的scala.runtime.NonLocalReturnException内容不会被捕获,并将向上传播到调用堆栈

于 2012-11-30T21:17:05.460 回答
1

在 a 中,foreachreturn "1"在到达return "2"行之前执行。即使它在 foreach 中,代码仍会执行,因此它返回 1。在 b 中,x 是通过“自类型注释”(http://www.scala-lang.org/node/124)分配给操作的的return "1"

这篇关于 scala 继承的帖子可能有用:使用这个关键字来继承?

分享和享受

于 2012-11-30T21:17:12.853 回答