我和我的同事对以下代码的行为感到有点困惑。
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
到底是什么时候被评估的?
答案 0 :(得分:12)
表格的所有*功能评估
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 }
并在未经评估的情况下传入。
答案 1 :(得分: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
};
答案 2 :(得分:1)
那真的很酷 - 我不知道。查看语言参考,http://www.scala-lang.org/docu/files/ScalaReference.pdf的第91页:
返回表达式返回 e 必须出现在一些封闭的名称的主体内 方法或功能。最里面的封闭命名方法或函数 源程序 f 必须具有显式声明的结果类型,以及 e 的类型 必须符合它。返回表达式计算表达式e并返回它 值为 f 的结果。
...
由编译器生成的
apply
方法作为匿名函数的扩展,不计入源程序中的命名函数,因此永远不会成为返回表达式的目标。通过抛出并捕获
scala.runtime.NonLocalReturnException
来实现从嵌套匿名函数返回。返回点和封闭方法之间的任何异常捕获都可能会看到异常。密钥比较确保这些异常仅由返回终止的方法实例捕获。如果返回表达式本身是匿名函数的一部分,则可能是 在执行返回表达式之前,已经返回了 f 的封闭实例。在这种情况下,抛出的
scala.runtime.NonLocalReturnException
不会 被抓住,并将传播到调用堆栈
答案 3 :(得分:1)
在a中,foreach在到达return "1"
行之前执行return "2"
。即使认为它是在foreach中代码仍然执行,因此它返回1.在b中,x通过“自我类型注释”(http://www.scala-lang.org/node/124)分配给return "1"
的操作
关于scala继承的这篇文章可能有用:Using this keyword to inherit?
分享并享受
答案 4 :(得分:1)
Scala使用急切的应用订单评估。这意味着在替换函数的参数之前评估参数。此外,值得回顾的是,功能可以自我评估。函数 application 评估函数的返回值。现在让我们看看每个参数评估的内容。
scala> :t () => "1"
() => java.lang.String
所以,在第二种情况下,我们得到一个函数。它在传递之前被评估(自身),但从未应用,因为None
没有元素。但是,不需要应用return "1"
。它只需要进行评估,它具有重定向控制的副作用,然后从包含它的函数返回“1”。