Scala函数重载异常

Scala Function Overloading Anomaly

在 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)

为什么不抛出异常?如果使用默认值,我会认为这两个定义看起来是一样的。

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

Otherwise, let CC be the set of applicable alternatives which don't employ any default argument in the application to e1,…,em.

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

public class testing.ReadingFile$log {
  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();
    Code:
       0: aconst_null
       1: areturn
}

您看到生成的代码实际上发出了两种方法,一种采用两个参数,一种采用三个。此外,编译器添加了一个名为 LogInfo$default 的附加方法(名称实际上有含义,其中 </code> 表示“第三个参数的默认参数”),其中 returns 默认值<code>c 第二个重载的变量。如果要调用具有默认参数的方法,LogInfo$default 将用于引入具有给定值的新变量。

这两种方法都适用,但重载解析专门抛弃了需要默认args的应用程序:

applicable alternatives which don't employ any default argument

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

至于"why",想象重载有很多默认参数,这样它的大多数应用看起来不像是对第一个方法的调用。