Scala 函数重载异常

Posted

技术标签:

【中文标题】Scala 函数重载异常【英文标题】:Scala Function Overloading Anomaly 【发布时间】:2017-02-14 07:59:15 【问题描述】:

在 Scala 中,为什么允许这种重载?

class log 
  def LogInfo(m: String, properties: Map[String, String]): Unit = 
    println(m)
  

  def LogInfo(m: String, properties: Map[String, String], c: UUID = null): Unit = 
    println(m + c.toString())
  

在 LogInfo 函数的第二个定义中,我将额外参数设置为默认值 null。当我进行以下调用时,它将调用第一个重载。

val l: log = new log()
val props: Map[String, String] = Map("a" -> "1")
l.LogInfo("message", props)

为什么它不会抛出异常?如果使用默认值,我会认为这两个定义可能看起来相同。

【问题讨论】:

"如果使用默认值,我会认为这两个定义可能看起来相同。"你有任何证据支持这个想法,还是只是猜测? 为什么会抛出异常? 我应该说编译错误,而不是异常。 【参考方案1】:

这里不会抛出异常,因为编译器选择第一个重载作为适用的重载。这与the way overload resolution works with default arguments 有关。根据规范,强烈暗示此类方法被丢弃的事实将是以下行:

否则,让 CC 成为一组适用的替代方案e1,…,em 的应用程序中不使用任何默认参数。

这与 Scala 编译器为这两种方法生成 JVM 字节码的方式有关。如果我们编译它们并查看幕后,我们会看到(为简洁起见,省略实际的字节码):

public class testing.ReadingFile$log$1 
  public void LogInfo(java.lang.String,
                      scala.collection.immutable.Map<java.lang.String, java.lang.String>);
    Code:

  public void LogInfo(java.lang.String,
                      scala.collection.immutable.Map<java.lang.String, java.lang.String>,
                      java.util.UUID);
    Code:

  public java.util.UUID LogInfo$default$3();
    Code:
       0: aconst_null
       1: areturn

您会看到生成的代码实际上发出了两种方法,一种采用两个参数,一种采用三个参数。另外,编译器添加了一个额外的方法,叫做LogInfo$default$3(这个名字其实是有含义的,其中$3的意思是“第三个参数的默认参数),它返回第二个重载的c变量的默认值. 如果要调用具有默认参数的方法,LogInfo$default$3 将用于引入具有给定值的新变量。

【讨论】:

【参考方案2】:

这两种方法都适用,但是重载解析会特别抛弃需要默认参数的应用程序:

不使用任何默认参数的适用替代方案

http://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolution

至于“为什么”,想象一下重载有很多默认参数,因此它的大多数应用程序看起来不像是第一个方法的调用。

【讨论】:

以上是关于Scala 函数重载异常的主要内容,如果未能解决你的问题,请参考以下文章

如果我在 Scala 中定义多个重载构造函数,我不能定义默认值吗?

为啥在析构函数中抛出异常时不调用重载删除?

Scala编程--函数式对象

重载和重写有啥区别

快学Scala 第二课 (apply, if表达式,循环,函数的带名参数,可变长参数,异常)

重写与重载的区别