在Scala中为什么不建议用return
在Scala 中使用return的话,编译的时候会提示 :
the lastest statement is method is automatically returned ,use of th return keyword is redundant(多余的)
1. 要写函数而不是指令
函数式编程的一个重要理念就是要尽量使用代码由无状态的函数构成,而不是给计算机发出指令.
eg:
f(x) = x+1 //式1.1
是一个函数.
scala 会自动将最后一个表达式的结果作为返回结果
eg:
def f(x:Int)= x+1//式1.2
def f(x:Int):Int = return x+1// 式1.3
从以上两种分别使用和不适用return 的表达式来看,不适用return看起来更接近函数,而使用return 则更像指令)
2. return 影响类型判断
由于Scala中的类型自动推断机制,会自动将最后一个表达式的类型作为返回类型,
如果使用了return语句,就会破坏类型推断机制,需要显示注明返回类型
3. 使用return 返回含义模糊
def add(n:Int, m:Int): Int = return n + m //式3.1
def sum1(ns: Int*): Int = ns.foldLeft(0)(add) //式3.2
1
2
例如上述代码,目前来看还没有什么问题,但是如果写成下面的形式
def sum2(ns: Int*): Int = ns.foldLeft(0)((n,m) => return n+m) //式3.3
1
直观感受式3.3与3.1+3.2应该是等效的。但事实上sum1(1,2,3) = 6,而sum2(1,2,3) = 1.
原因就是return语句会直接让它所出现的函数返回。也就会直接break foldLeft的循环返回结果。
再看另外一个例子:
def foo: Int = {
val sumR: List[Int] => Int = _.foldLeft(0)((n, m) => return n + m)
sumR(List(1,2,3)) + sumR(List(4,5,6))
}
1首先定义一个匿名函数,在调用匿名函数的时候,相当于return语句出现在了foo函数中。因此foo() = 1
4.NonLocalReturnControl
在scala的循环中的return实际上是通过抛异常实现的,编译后发现
return value
1
被编译成了
throw new NonLocalReturnControl(key/*metadata*/, value)
1
而NonLocalReturnControl的源码为:
class NonLocalReturnControl[@specialized T](val key: AnyRef, val value: T) extends ControlThrowable {
final override def fillInStackTrace(): Throwable = this
}
可以看到NonLocalReturnControl异常继承了Throwable,并且为了提升性能重写了fillInStackTrace不填入堆栈信息。这样一来,如果我们在代码中为了保护代码不crash而这样写:
def fun(n:Int):String = {
try {
for(i <- 0 to n){
if(i < 5){
}else{
return "gt"
}
}
""
}catch{
case t:Throwable => return t.toString
}
}
1
最终得到的结果字符串则为scala.runtime.NonLocalReturnControl,并不是我们预期的结果。
5.应当怎么做
实际开发中我们会经常遇到貌似必须使用return的时候,那应该怎么办呢?首先,scala既然提供了return关键字,说明它并不是禁止使用,而是需要考虑清楚是否必须这么做。在scala认为,所有的需要使用return来break的循环,都是可以通过转化为递归来替代的,并且性能方面scala也专门为递归做了优化。