• Scala 中为什么不建议用 return 关键字


    在scala中使用 return 的话,编译的时候会提示the latest statement is method is automatically returned, use of th return keyword is redundant.

    这个警告是说最后一个语句的结果会自动返回,不需要使用return语句。 scala 不建议使用 return 关键字,这一点在刚刚接触函数式编程的时候感觉非常难受。

    有 return 会让代码结果更清晰不是么?在查阅之后,整理了以下几点不建议使用 return 关键字的原因。

    1.要写函数而不是指令

    函数式编程的一个重要理念就是要尽量使代码由无状态的函数构成,而不是给计算机发出指令。例如

    f(x) = x + 1    //式1.1
    1
    

    是一个函数。
    scala会自动将最后一个表达式的结果作为返回结果

    def f(x:Int) = x + 1    //式1.2
    def f(x:Int):Int = return x + 1     //式1.3
    12
    

    从以上两种分别使用和不使用 return 的表达方式来看,不使用 return 看起来更接近函数,而使用了 return 则更像指令。

    2.return影响类型推断

    scala中的类型推断机制会自动将最后一个表达式的类型作为返回类型,例如式1.2中,函数能够自动识别结果为Int类型。如果使用了return语句,就会破坏类型推断机制,需要显式注明返回类型,例如式1.3。

    3.使用return返回含义模糊

    有时使用了return会让代码的返回更加混乱,这个歧义主要产生于return到底返回到哪一层函数。

    def add(n:Int, m:Int): Int = return n + m     //式3.1
    def sum1(ns: Int*): Int = ns.foldLeft(0)(add)    //式3.2
    12
    

    例如上述代码,目前来看还没有什么问题,但是如果写成下面的形式

    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))
    }
    1234
    

    首先定义一个匿名函数,在调用匿名函数的时候,相当于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
    }
    123
    

    可以看到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
        }
    }
    12345678910111213
    

    最终得到的结果字符串则为scala.runtime.NonLocalReturnControl,并不是我们预期的结果。

    5.应当怎么做

    实际开发中我们会经常遇到貌似必须使用return的时候,那应该怎么办呢?

    首先,scala既然提供了 return 关键字,说明它并不是禁止使用,而是需要考虑清楚是否必须这么做。在scala认为,所有的需要使用 return 来 break 的循环,都是可以通过转化为递归来替代的,并且性能方面 scala 也专门为递归做了优化。

    作者:Binge
    本文版权归作者和博客园共有,转载必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    ios之单例模式
    ios之申请后台延时执行和做一个假后台的方法
    ios之gcd浅析
    ios之归档demo
    ios之快速领会VFL的demo
    ios之网络异常与正常视图的切换
    POJ 2280 Amphiphilic Carbon Molecules 极角排序 + 扫描线
    linux pthread
    directdraw显示yuv422(yuy2)
    nginx高效学习方法
  • 原文地址:https://www.cnblogs.com/binbingg/p/14107456.html
Copyright © 2020-2023  润新知