sem*_*ema 4 generics casting scala scala-java-interop
我正在尝试实现包装数学Java函数的泛型函数。为简单起见,我们可以假定Java函数(Java 7)接受一个参数并返回结果,均为java.lang.Double类型。当然,包装器函数应该带有一个参数和一个结果,它们都是通用类型但为数字类型A。问题是我无法在包装器函数中将结果强制转换回类型A。问题出在哪里/什么地方?
注意:(我是Scala的新手,并使用以下参考资料来解决该问题。)
package test
object mytest {
def f[A](x: A)(implicit num: Numeric[A]): A = {
val result = new java.lang.Double(num.toDouble(x))
result.asInstanceOf[A]
}
def main(args: Array[String]) {
// 'Some code'
}
}
Run Code Online (Sandbox Code Playgroud)
result val result = f(3)
Run Code Online (Sandbox Code Playgroud)
输出:
Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
at test.mytest$.main(test.scala:10)
at test.mytest.main(test.scala)
Run Code Online (Sandbox Code Playgroud)
println(f(3))
Run Code Online (Sandbox Code Playgroud)
输出:
3.0
Run Code Online (Sandbox Code Playgroud)
println(f(3).getClass)
Run Code Online (Sandbox Code Playgroud)
输出:
int
Run Code Online (Sandbox Code Playgroud)
package test
object mytest {
def f[A : Manifest](x: A)(implicit num: Numeric[A]): A = {
val result = new java.lang.Double(num.toDouble(x))
manifest[A].erasure.cast(result).asInstanceOf[A]
}
def main(args: Array[String]) {
val result = f(3)
}
}
Run Code Online (Sandbox Code Playgroud)
(对于变体A1,A2和A3的等效项也是如此,因为现在在函数f的第6行中引发了异常。)
Exception in thread "main" java.lang.ClassCastException: Cannot cast java.lang.Double to int
at java.lang.Class.cast(Class.java:3176)
at test.mytest$.f(test.scala:6)
at test.mytest$.main(test.scala:10)
at test.mytest.main(test.scala)
Run Code Online (Sandbox Code Playgroud)
你可以不投Double给Integer反正(因为它是盒装)。Numeric只是允许您import num._在T上进行一组数学运算(by )-别无其他(您不需要某种中介类型)。A2之所以有效是因为println所期望Any的f(3),因此T自动推断为Any; println(f[Int](3))永远不会工作,f[Any](3)永远都会工作。
如果要实现操作Doubles的泛型函数(仅当您具有Double特定的操作时才需要)-最好返回Double。如果不能,则必须通过分析T来手动构造类型:
def f[A](x: A)(implicit num: Numeric[A]): A = {
val result = new java.lang.Double(num.toDouble(x))
(x match {
case x: Double => result
case x: Int => result.toInt
case x: Float => result.toFloat
case x: Long => result.toLong
}).asInstanceOf[A]
}
Run Code Online (Sandbox Code Playgroud)
您不能只在result.doubleValue.asInstanceOf[A]这里做的原因是A已装箱。@specialized注释不适用于asInstanceOf(类型A仍为方框)
更新:实际@specialized工作:
def f[@specialized(Int, Double, Long, Float) A](x: A)(implicit num: Numeric[A]): A = {
val result = new java.lang.Double(num.toDouble(x))
result.doubleValue.asInstanceOf[A]
}
Run Code Online (Sandbox Code Playgroud)
但这在Scala REPL中不起作用 -请当心!
PS清单已弃用:使用classTag/ typeTag代替