在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 也专门为递归做了优化。

Scala 中为什么不建议用 return 关键字的更多相关文章

  1. Java中处理异常中return关键字

    Java中,执行try-catch-finally语句需要注意: 第一:return语句并不是函数的最终出口,如果有finally语句,这在return之后还会执行finally(return的值会暂 ...

  2. 第2节 Scala中面向对象编程:7、继承的概念以及override和super关键字;8、isInstanceOf 和 asInstanceOf关键字

    6.3.   Scala面向对象编程之继承 6.3.1.     Scala中继承(extends)的概念 Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字: 继承 ...

  3. Programming In Scala笔记-第七章、Scala中的控制结构

    所谓的内建控制结构是指编程语言中可以使用的一些代码控制语法,如Scala中的if, while, for, try, match, 以及函数调用等.需要注意的是,Scala几乎所有的内建控制结构都会返 ...

  4. Scala学习(五)---Scala中的类

    Scala中的类 摘要: 在本篇中,你将会学习如何用Scala实现类.如果你了解Java或C++中的类,你不会觉得这有多难,并且你会很享受Scala更加精简的表示法带来的便利.本篇的要点包括: 1. ...

  5. Programming In Scala笔记-第十一章、Scala中的类继承关系

    本章主要从整体层面了解Scala中的类层级关系. 一.Scala的类层级 在Java中Object类是所有类的最终父类,其他所有类都直接或间接的继承了Object类.在Scala中所有类的最终父类为A ...

  6. [转] Scala 中的异步事件处理

    在任何并发性应用程序中,异步事件处理都至关重要.无论事件的来源是什么(不同的计算任务.I/O 操作或与外部系统的交互),您的代码都必须跟踪事件,协调为响应它们而执行的操作.应用程序可以采用两种基本方法 ...

  7. 异常处理机制中的return关键字

    Java中,执行try-catch-finally语句需要注意: 第一:return语句并不是函数的最终出口,如果有finally语句,这在return之后还会执行finally(return的值会暂 ...

  8. 大数据学习之Scala中main函数的分析以及基本规则(2)

    一.main函数的分析 首先来看我们在上一节最后看到的这个程序,我们先来简单的分析一下.有助于后面的学习 object HelloScala { def main(args: Array[String ...

  9. scala学习手记16 – scala中的static

    前面两节学了scala的对象和伴生对象,这两个在使用的时候很有些java的静态成员的意思. scala中没有静态字段和静态方法.静态成员会破坏scala所支持的完整的面向对象模型.不过可以通过伴生对象 ...

随机推荐

  1. JVM--Java核心面试知识整理(一)

    JVM 基本概念 JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集.一组寄存器.一个栈. 一个垃圾回收,堆和 一个存储方法域.JVM 是运行在操作系统之上的,它与硬件没有直接的交互 ...

  2. MySQL数据库高级五:主从复制

    主机只能一台 从机去复制 单表500万上限

  3. Sentinel上生产环境只差一步,监控数据持久化

    之前介绍了Sentinel相关的文章,小伙伴在生产实践中不知道有没有这个疑问?我们的Sentinel控制台监控的数据只能看最近5分钟的,如图 那么就导致历史数据是查看不了的,那肯定是不行的,在生产环境 ...

  4. 0ctf_2017_babyheap

    0ctf_2017_babyheap 首先检查一下保护 IDA 分析好的代码如下 首先申请了一块内存地址用来存放结构体数组,地址随机. 堆题常见的几个功能.我们来看看add 这里申请内存用的是call ...

  5. 使用docker快速安装软件

    安装mysql mkdir /opt/mysql /opt/mysql/etc /opt/mysql/data docker run -itd --name mariadb -e MYSQL_ROOT ...

  6. Rabbitmq 3.6.5以上版本修改端口号方法

    Rabbitmq 3.6.5以上版本修改端口号方法,网上查了下有一些方不管用,所以自己实践了引用官网说明 https://www.rabbitmq.com/configure.html#configu ...

  7. python 自动化审计

    基于python的自动化代码审计 代码审计 逢魔安全实验室   2018-02-11  10,539   本文通过介绍在python开发中经常出现的常规web漏洞,然后通过静态和动态两种方式对pyth ...

  8. 利用 Windows 线程池定制的 4 种方式完成任务(Windows 核心编程)

    Windows 线程池 说起底层的线程操作一般都不会陌生,Windows 提供了 CreateThread 函数来创建线程,为了同步线程的操作,Windows 提供了事件内核对象.互斥量内核对象.关键 ...

  9. 你注意到了吗?修改API文档也需要规范!

    关于API接口文档的内容和格式规范的文章,之前也有写过,网上也有不少写的比我还好的,就不赘述了,今天想说的是一个很容易被忽略的点,修改API文档的规范:版本控制. 示例 拿Eolinker来演示一下流 ...

  10. IDEA只有Commit没有Push按钮

    问题描述 idea的右上角只有commit按钮,而没有push按钮 问题解决 打开File->Settings->Menus and Toolbars->Navigation Bar ...