Scala 尽管@specialized,但由于类型擦除而导致方法重复

Scala 尽管@specialized,但由于类型擦除而导致方法重复,scala,type-erasure,Scala,Type Erasure,我被那件事绊倒了 def foo(f: Int => Unit) {} def foo(f: Long => Unit) {} 由于方法foo被定义了两次,因此无法编译。我知道上面只是一个简写 def foo(f: Function1[Int, Unit]) {} def foo(f: Function1[Long, Unit]) {} 在类型擦除之后,两种方法具有相同的签名 现在我已经了解到,自Scala 2.8以来,Function1和Function2有@专门的版本,用于I

我被那件事绊倒了

def foo(f: Int => Unit) {}
def foo(f: Long => Unit) {}
由于方法foo被定义了两次,因此无法编译。我知道上面只是一个简写

def foo(f: Function1[Int, Unit]) {}
def foo(f: Function1[Long, Unit]) {}
在类型擦除之后,两种方法具有相同的签名

现在我已经了解到,自Scala 2.8以来,
Function1
Function2
@专门的
版本,用于
Int
Long
Double
。这当然意味着
Function[Int,Unit]
Function[Long,Unit]
在JVM级别有单独的类文件

那么,两个签名不是都不同吗

问题是,第二个类型参数将继续被擦除?但同样的问题

class Bar[@specialized T]
def foo(f: Bar[Int]) {}
def foo(f: Bar[Long]) {}

它不会编译。

对于兼容性和
Function1
的类型参数未知的情况,还必须生成一个签名为
Function1
未专门化的方法。

@specialized与类型擦除无关,至少在这种情况下是这样。这意味着将生成一个额外版本的类,其中本地类型位于该位置。这显著节省了装箱/拆箱时间

因此您定义了一个类,如:

class MyClass[@specialized(Int) T] {
  def foobar(t: T) = {}
}
得到两个类作为输出,(大约):

您需要有两个类的实现,因为您不能总是保证调用具有正确本机类型的实现。scala编译器将选择调用哪一个。请注意,java编译器不知道这种专门化正在发生,因此必须调用非专门化的方法

事实上,输出如下(通过JAD):

因此,您的类型擦除问题不会用@specialized解决。

特别是受的启发,我尝试了以下方法

class Bar[@specialized(Int) T](val t: T)
class Foo {
  def foo(b: Bar[_]) { print(b.t) }
}
val bari = new Bar(1)
print(bari.t)
foo(bari)
使用
scalac-打印
并获得:

// unspecialized version Bar[_] = Bar[Object]
class Bar extends Object with ScalaObject {
  protected[this] val t: Object = _;
  def t(): Object = Bar.this.t;
  def t$mcI$sp(): Int = Int.unbox(Bar.this.t());
  def specInstance$(): Boolean = false;
  def this(t: Object): Bar = {
    Bar.this.t = t;
    Bar.super.this();
    ()
  }
};
// specialized version Bar[Int]
class Bar$mcI$sp extends Bar {
  protected[this] val t$mcI$sp: Int = _;
  // inside of a specialized class methods are specialized,
  // so the `val t` accessor is compiled twice:
  def t$mcI$sp(): Int = Bar$mcI$sp.this.t$mcI$sp;
  override def t(): Int = Bar$mcI$sp.this.t$mcI$sp();
  def specInstance$(): Boolean = true;
  override def t(): Object = Int.box(Bar$mcI$sp.this.t());
  def this(t$mcI$sp: Int): Bar$mcI$sp = {
    Bar$mcI$sp.this.t$mcI$sp = t$mcI$sp;
    Bar$mcI$sp.super.this(null);
    ()
  }
}
class Foo extends Object with ScalaObject {
  // scalac compiles only ONE foo method not one for every special case
  def foo(b: Bar): Unit = Predef.print(b.t());
  def this(): Foo = {
    Foo.super.this();
    ()
  }
};
val bari: or.gate.Bar = new or.gate.Bar$mcI$sp(1);
// specialized version of `val t` accessor is used:
Predef.print(scala.Int.box(bari.t$mcI$sp()));
Foo.this.foo(bari)

但是通过
foo
仅使用
val t
访问器的非专用版本,即使对于专用实例
bari
和间接
bari
的重写方法
def t():Object=Int.box(Bar$mcI$sp.this.t())被调用。

这是否意味着如果我自动定义
def-foo(f:Bar[T]){}
编译器真的定义了
def-foo(f:Bar[Int]){}
def-foo(f:Bar[Long]){}
并且不需要显式定义它们?@binuWADa:不,请看。
class Bar[@specialized(Int) T](val t: T)
class Foo {
  def foo(b: Bar[_]) { print(b.t) }
}
val bari = new Bar(1)
print(bari.t)
foo(bari)
// unspecialized version Bar[_] = Bar[Object]
class Bar extends Object with ScalaObject {
  protected[this] val t: Object = _;
  def t(): Object = Bar.this.t;
  def t$mcI$sp(): Int = Int.unbox(Bar.this.t());
  def specInstance$(): Boolean = false;
  def this(t: Object): Bar = {
    Bar.this.t = t;
    Bar.super.this();
    ()
  }
};
// specialized version Bar[Int]
class Bar$mcI$sp extends Bar {
  protected[this] val t$mcI$sp: Int = _;
  // inside of a specialized class methods are specialized,
  // so the `val t` accessor is compiled twice:
  def t$mcI$sp(): Int = Bar$mcI$sp.this.t$mcI$sp;
  override def t(): Int = Bar$mcI$sp.this.t$mcI$sp();
  def specInstance$(): Boolean = true;
  override def t(): Object = Int.box(Bar$mcI$sp.this.t());
  def this(t$mcI$sp: Int): Bar$mcI$sp = {
    Bar$mcI$sp.this.t$mcI$sp = t$mcI$sp;
    Bar$mcI$sp.super.this(null);
    ()
  }
}
class Foo extends Object with ScalaObject {
  // scalac compiles only ONE foo method not one for every special case
  def foo(b: Bar): Unit = Predef.print(b.t());
  def this(): Foo = {
    Foo.super.this();
    ()
  }
};
val bari: or.gate.Bar = new or.gate.Bar$mcI$sp(1);
// specialized version of `val t` accessor is used:
Predef.print(scala.Int.box(bari.t$mcI$sp()));
Foo.this.foo(bari)