偶然发现了
def foo(f: Int => Unit) {}
def foo(f: Long => Unit) {}
由于method foo is defined twice
,无法编译。我知道上面只是
的简写def foo(f: Function1[Int, Unit]) {}
def foo(f: Function1[Long, Unit]) {}
并且在类型擦除之后,两种方法都具有相同的签名。
现在我在Try out specialized Function1/Function2 in 2.8.0 RC1!中读到Function1
和Function2
@specialized
Int
,Long
和Double
版本自Scala 2.8起。这肯定意味着Function[Int, Unit]
和Function[Long, Unit]
在JVM级别具有单独的类文件。
那么两个签名都不会有所不同吗?
问题是,第二个类型参数将继续被删除吗?但与
相同的问题class Bar[@specialized T]
def foo(f: Bar[Int]) {}
def foo(f: Bar[Long]) {}
它无法编译。
答案 0 :(得分:6)
@specialized与类型擦除无关,至少在这种情况下。这意味着将使用位置中的本机类型生成类的额外版本。这显着节省了装箱/拆箱。
所以你定义了一个类:
class MyClass[@specialized(Int) T] {
def foobar(t: T) = {}
}
你得到两个类作为输出,(大约):
class Foobar[java.lang.Object] {
def foobar(t: java.lang.Object) = {}
}
class Foobar[int] {
def foobar(t: int) = {}
}
您需要拥有该类的两个实现,因为您无法始终保证将调用具有正确本机类型的实现。 scala编译器将选择要调用的编译器。请注意,java编译器不知道正在进行此专业化,因此必须调用非专用方法。
实际上,输出如下(通过JAD):
public class MyClass implements ScalaObject {
public void foobar(Object obj) { }
public void foobar$mcI$sp(int t) {
foobar(BoxesRunTime.boxToInteger(t));
}
public MyClass() { }
}
public class MyClass$mcI$sp extends MyClass {
public void foobar(int t) {
foobar$mcI$sp(t);
}
public void foobar$mcI$sp(int i) { }
public volatile void foobar(Object t) {
foobar(BoxesRunTime.unboxToInt(t));
}
public MyClass$mcI$sp() {}
}
所以你的类型擦除问题不会被@specialized修复。
答案 1 :(得分:3)
对于兼容性和Function1
的类型参数未知的情况,还必须生成具有签名的方法,如同Function1
不是专用的。
答案 2 :(得分:0)
尤其受到Matthew Farwell答案的启发我尝试了以下
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 -print
并获得:
// 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
的重写方法{{ 1}}被称为。