【问题标题】:Type erasure with parameter defaults使用参数默认值进行类型擦除
【发布时间】:2013-09-18 15:13:51
【问题描述】:

以下内容无法编译:

package play

object Stats2 {
  def variance(data: Seq[Double], dof: Int = 0): Double = {
    println("variance Double direct"); 1.0
  }
  def variance[T](data:Seq[T], dof: Int = 0)(implicit ex: T => Double): Double = {
    println("variance Double extracted"); 1.0
  }
} 

编译器说:

$ scalac erasure2.scala 
erasure2.scala:7: error: double definition:
method variance$default$2:[T]=> Int and
method variance$default$2:=> Int at line 4
have same type after erasure: ()Int
  def variance[T](data:Seq[T], dof: Int = 0)(implicit ex: T => Double): Double = {
                               ^
one error found

如果将 dof :Int = 0 更改为 dof: Int,则示例编译并按预期工作。

无论代码是否有效,默认参数值的存在与否都会改变,这似乎很难看。

为什么这真的有意义的解释是什么?

【问题讨论】:

  • 第一个完全有意义,因为在 Scala 方法重载中仅通过检查第一个参数并且由于类型擦除它是相同的,因此错误。做dof:Int 很奇怪。我在手册中没有看到任何推理

标签: scala type-erasure default-parameters


【解决方案1】:

问题是当你使用默认参数时,它的名字和方法名被用来生成一个静态属性,这样:[methodName]$default$[argumentPosition],在你的情况下它将是variance$default$2,所以如果两者都有默认参数,编译器会尝试生成2个同名的静态属性。

如果使用方法中其他参数的类型,则可以避免这种情况。您可以submit a SIP 建议在编译器中更改此行为。

您可以在 post 上阅读更多相关信息

如果您想自己检查,请尝试使用每种方法编译您的对象并使用javap [XXX] 检查类,其中是对象或类的名称,在您的情况下为javap Stats2
您的第一种方法将给出:

public final class Stats2 extends java.lang.Object{
    public static final int variance$default$2();
    public static final double variance(scala.collection.Seq, int);
}

你的第二种方法会给出:

public final class Stats2 extends java.lang.Object{
    public static final int variance$default$2();
    public static final double variance(scala.collection.Seq, int, scala.Function1);
}

最后,通过去除第二种方法中dof的默认值,我们得到:

public final class Stats2 extends java.lang.Object{
    public static final double variance(scala.collection.Seq, int, scala.Function1);
}

所以static final int variance$default$2()是导致编译失败的原因,它是由默认值生成的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多