是否可以动态强制在scala中运行时装箱?我想要一个功能:
def box(value :Any) :AnyRef
Run Code Online (Sandbox Code Playgroud)
要么
def box[T](value :T) :AnyRef
Run Code Online (Sandbox Code Playgroud)
我有一个泛型类,可以使用AnyVals进行参数化,但需要将它们传递给接受对象集合的旧Java方法.当然,我可以自己使用模式匹配来实现它,但是它必须一次又一次地做它有点烦人,并且它对用户值类不起作用.
编辑
答案变得简单,令人惊讶.现在,我可以通过反思来做到吗?假设
class Box[T :TypeTag](private var value :T) {
def get :T = value
def set(o :Any) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
我想做一个安全集,检查运行时是否o是T的子类,如下所示:
runtimeMirror(getClass.getClassLoader).classSymbol(o.getClass).toType <:< typeOf[T]
Run Code Online (Sandbox Code Playgroud)
不幸的是,Box [Long]的typeOf [T]将是一个原语,并且以下检查将在java.lang.Long上失败,例如,Seq [Long]的元素的运行时类型.最后,当使用泛型与AnyVals时,编译器有时会将它们设置为使得运行时类检查不可预测.
刚加入AnyRefwith asInstanceOf,Scala会将其变成AnyRef:
scala> val x = 13
x: Int = 13
scala> val xBoxed = x.asInstanceOf[AnyRef]
xBoxed: AnyRef = 13
scala> xBoxed.getClass()
res0: Class[_ <: AnyRef] = class java.lang.Integer
Run Code Online (Sandbox Code Playgroud)
对于值类,这会将其装在值类的实例中,而不是Java类中。您可以使用通用特征来从值类中获取Java盒装版本,而无需使用反射。例如:
trait ValueClass[T] extends Any {
def value: T
def javaBoxed: AnyRef = value.asInstanceOf[AnyRef]
}
case class MyInt(value: Int) extends AnyVal with ValueClass[Int]
case class MyReal(asDouble: Double) extends AnyVal with ValueClass[Double] {
def value = asDouble
}
Run Code Online (Sandbox Code Playgroud)
但是,这要求您将自己的特质混合到所有价值类别中。对于扩展的值类Product(如所有案例类一样),可以使用productElement以下更快的方法:
def javaBox(x: Product): AnyRef = {
if (x.productArity == 1) x.productElement(0).asInstanceOf[AnyRef]
else x.asInstanceOf[AnyRef] // or throw an exception if you prefer
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,在我看来,这两种方法(mix-in trait和Product)都导致Scala进行装箱,这意味着在调用未装箱的值时,该值来自未装箱的?斯卡拉盒装?拆箱?用Java装箱,而不是直接使用Java装箱值。
| 归档时间: |
|
| 查看次数: |
698 次 |
| 最近记录: |