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)