Mik*_*fey 5 scala type-erasure default-parameters
以下内容无法编译:
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
}
}
Run Code Online (Sandbox Code Playgroud)
编译器说:
$ 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
Run Code Online (Sandbox Code Playgroud)
如果dof:Int = 0更改为dof:Int,则示例将按预期编译并运行.
无论代码是否有效,默认参数值的存在与否都会发生变化,这似乎很难看.
为什么这才真正有意义的解释是什么?
问题是,当你使用默认参数时,它的名称和方法名称用于生成静态属性,这样:[methodName]$default$[argumentPosition]在你的情况下它将是variance$default$2,所以如果两者都有默认参数,编译器将尝试生成2静态具有相同名称的属性.
如果使用方法中其他参数的类型,则可以避免这种情况.您可以提交SIP提议以在编译器中更改此行为.
如果您想自己检查,请尝试使用每种方法编译对象,并使用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);
}
Run Code Online (Sandbox Code Playgroud)
而你的第二种方法将给出:
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);
}
Run Code Online (Sandbox Code Playgroud)
最后,通过在第二种方法中删除dof的默认值,我们得到:
public final class Stats2 extends java.lang.Object{
public static final double variance(scala.collection.Seq, int, scala.Function1);
}
Run Code Online (Sandbox Code Playgroud)
所以,static final int variance$default$2()是什么让编译失败的原因,这是由默认值产生的.