我试图实现一个包含数学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'
}
}
result val result = f(3)
输出:
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)
println(f(3))
输出:
3.0
println(f(3).getClass)
输出:
int
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)
}
}
(对于变体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)
答案 0 :(得分:4)
无论如何,您无法将Double
投放到Integer
(因为它是盒装的)。 Numeric
只允许你对你的T进行一系列数学运算(import num._
) - 没有别的(你不需要一些中介类型)。 A2仅因为println因Any
而期待f(3)
而有效,因此T
会自动推断为Any
; println(f[Int](3))
永远不会有效,f[Any](3)
将永远有效。
如果你想实现操作双打的通用功能(只有当你有特定于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]
}
你不能在这里做result.doubleValue.asInstanceOf[A]
的原因是A已经装箱了。 @specialized
注释不适用于asInstanceOf
(type A is still boxed)
更新:实际上@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]
}
但它doesn't work in Scala REPL - 所以要小心!
P.S。不推荐使用清单:使用classTag
/ typeTag
代替