如何将 Any 转换为 Array[T] 保持数组的 Scala 不变性



我尝试在JVM数组上实现以下函数来维护Scala的不变视图:

def cast[T](a: Any): Option[Array[T]] = ???

即给定:

class Foo
class Bar extends Foo

我希望下面的例子返回Some:

val arr1: Any = Array(new Bar)
cast[Bar](arr1) // OK
val arr2: Any = Array(1, 2, 3)
cast[Int](arr2) // OK
val arr3: Any = Array("a", "b", "c")
cast[String](arr3) // OK

对于下面这个,我希望它返回None:

val arr: Any = Array(new Bar)
cast[Foo](arr1) // I want it to be None
val arr2: Any = Array(List(new Bar))
cast[List[Foo]](arr2) // this must be None too!

我尝试通过反射使用ClassTag/TypeTag没有运气,但由于我不是反射专家,我可能会错过一些东西。

注::我知道有Any在那里,是一个不好的做法,但是,请尝试看到问题学术。你知道,只是想知道是否有办法做到这一点,以及如何做到。

更新:由于类型擦除,下面提供的解决方案仍然不适用于Array(List(new Bar))

我想这就是你想要的:

import scala.reflect.ClassTag
def cast[T](a: Any)(implicit ct: ClassTag[Array[T]]): Option[Array[T]] = ct.unapply(a)

在REPL中:

scala> val x: Any = Array(1, 2, 3)
x: Any = Array(1, 2, 3)
scala> val y = cast[Int](x)
y: Option[Array[Int]] = Some([I@7a8f55c)
scala> val z = cast[String](x)
z: Option[Array[String]] = None

上面的解决方案不保持不变性;到目前为止,我发现最好的方法是:

def cast[T](in: Any)(implicit ct: ClassTag[Array[T]]): Option[Array[T]] = 
  if (ct.runtimeClass == in.getClass) ct.unapply(in) else None

不知道它有多好,但它工作:

scala> :paste
// Entering paste mode (ctrl-D to finish)
class Foo
class Bar extends Foo
val x: Any = Array(new Bar)
val y = cast[Foo](x)
val z = cast[Bar](x)
// Exiting paste mode, now interpreting.
defined class Foo
defined class Bar
x: Any = Array(Bar@6109a8cc)
y: Option[Array[Foo]] = None
z: Option[Array[Bar]] = Some([LBar;@7ccebaae)

相关内容

  • 没有找到相关文章

最新更新