据我所知,@specialized
注释应为我提到的每种基本类型生成一些未装箱的代码,但这不起作用:
scala> def aaa[@specialized(Int, Double, Float, Long) T] = (5.0).doubleValue.asInstanceOf[T]
aaa: [T]=> T
scala> aaa[Int]
unrecoverable error (inside interpreter/compiler)
编译:
scala> def aaa[@specialized(Int, Double, Float, Long) T](a: T) = (5.0).doubleValue.asInstanceOf[T]
aaa: [T]=> T
scala> aaa[Int](0)
ClassCastException
但它仍然使用盒装类型asInstanceOf [T]。这显然有效:
scala> (5.0).asInstanceOf[Int]
res28: Int = 5
更新:
键入擦除和类似Writing a generic cast function Scala的答案与我的问题无关。键入擦除只是阻止编译器为泛型添加typecast
字节码操作,但最终会添加 - 请参阅我的REPL中的ClassCastException
(由此操作生成)
答案 0 :(得分:3)
问题出在Scala REPL中 - @specialized
在那里不起作用。使用scalac编译def aaa[@specialized(Int) T] = (5.0).asInstanceOf[T]
会给出:
public <T> T aaa();
Code:
0: ldc2_w #15 // double 5.0d
3: invokestatic #22 // Method scala/runtime/BoxesRunTime
.boxToDouble:(D)Ljava/lang/Double;
6: areturn
public int aaa$mIc$sp();
Code:
0: ldc2_w #15 // double 5.0d
3: d2i
4: ireturn
d2i
正是我所期待的。当然,一切都可以正常使用scalac(所以我不需要为每种可能的类型进行模式匹配)。所以这只是带翻译的issue。
答案 1 :(得分:1)
该方法是专用的,但在单独的编译(即不同的行)下,不调用专门的方法。
在下文中,b.B.f
有效,c.B.f
已损坏。
$ scala -Xprint:typer,cleanup
scala> :pa -raw
// Entering paste mode (ctrl-D to finish)
package a { object A { def aaa[@specialized(Int) T] = (5.0).doubleValue.asInstanceOf[T] }}
package b { object B { def f = a.A.aaa[Int] }}
// Exiting paste mode, now interpreting.
[[syntax trees at end of typer]] // <pastie>
package <empty> {
package a {
object A extends scala.AnyRef {
def <init>(): a.A.type = {
A.super.<init>();
()
};
def aaa[@specialized(scala.Int) T]: T = scala.this.Predef.double2Double(5.0).doubleValue().asInstanceOf[T]
}
};
package b {
object B extends scala.AnyRef {
def <init>(): b.B.type = {
B.super.<init>();
()
};
def f: Int = a.A.aaa[Int]
}
}
}
[[syntax trees at end of cleanup]] // <pastie>
package <empty> {
package a {
object A extends Object {
def aaa(): Object = scala.Double.box(scala.this.Predef.double2Double(5.0).doubleValue());
<specialized> def aaa$mIc$sp(): Int = scala.this.Predef.double2Double(5.0).doubleValue().toInt();
def <init>(): a.A.type = {
A.super.<init>();
()
}
}
};
package b {
object B extends Object {
def f(): Int = a.A.aaa$mIc$sp();
def <init>(): b.B.type = {
B.super.<init>();
()
}
}
}
}
scala> :pa -raw
// Entering paste mode (ctrl-D to finish)
package c { object B { def f = a.A.aaa[Int] }}
// Exiting paste mode, now interpreting.
[[syntax trees at end of typer]] // <pastie>
package c {
object B extends scala.AnyRef {
def <init>(): c.B.type = {
B.super.<init>();
()
};
def f: Int = a.A.aaa[Int]
}
}
[[syntax trees at end of cleanup]] // <pastie>
package c {
object B extends Object {
def f(): Int = scala.Int.unbox(a.A.aaa());
def <init>(): c.B.type = {
B.super.<init>();
()
}
}
}
答案 2 :(得分:-1)
也许你只需要一个更新的编译器?这是我用2.11.2得到的:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_72).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def aaa[@specialized(Int, Double, Float, Long) T] = (5.0).doubleValue.asInstanceOf[T]
aaa: [T]=> T
scala> aaa[Int]
java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
... 33 elided
scala> aaa[Float]
java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Float
at scala.runtime.BoxesRunTime.unboxToFloat(BoxesRunTime.java:113)
... 33 elided
scala> aaa[Double]
res2: Double = 5.0
scala> 5.0.asInstanceOf[Int]
res3: Int = 5
scala> 5.0.asInstanceOf[Integer]
java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
... 33 elided
请注意,您可以直接5.0.asInstanceOf[Int]
但不能5.0.asInstanceOf[Integer]
。另请注意,使用aaa[Int]
获得的ClassCastException是指java.lang.Integer而不是Scala的Int类。我怀疑这里发生的是@specialized注释正在生成一个函数aaa
,它具有“Int”特化,但由于类型擦除和装箱将其转换为java.lang.Integer并且没有在Double和Integer之间使用asInstanceOf
进行自动转换。