我和我的同事对以下代码的行为感到有些困惑。
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
被执行?
我和我的同事对以下代码的行为感到有些困惑。
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
被执行?
形式的所有*功能评估
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 }
并传入而不进行评估。
其他人已经解释了这种行为,但最好不要使用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
};
Scala 使用急切的应用顺序评估。这意味着在替换函数的参数之前对参数进行评估。此外,值得回顾的是,函数对自己进行评估。它是函数应用程序,它计算函数的返回值。现在让我们看看每个参数的计算结果。
scala> :t () => "1"
() => java.lang.String
所以,在第二种情况下,我们得到了一个函数。它在通过之前被评估(对自身),但从未应用,因为None
没有元素。不过,return "1"
不需要申请。它只需要被评估,它具有重定向控制的副作用,然后从包含它的函数返回“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
内容不会被捕获,并将向上传播到调用堆栈
在 a 中,foreachreturn "1"
在到达return "2"
行之前执行。即使它在 foreach 中,代码仍会执行,因此它返回 1。在 b 中,x 是通过“自类型注释”(http://www.scala-lang.org/node/124)分配给操作的的return "1"
这篇关于 scala 继承的帖子可能有用:使用这个关键字来继承?
分享和享受