【发布时间】:2015-05-03 17:22:04
【问题描述】:
我想我已经接近开始理解类型擦除和 Scala 反射 API 了。但我仍然在一个痛苦的世界里......
我该如何处理这个问题?我有一个可以将泛型函数作为参数的类,我需要根据函数输出的类型做不同的事情。我还需要能够“提取”类型。 (这都与我的another question有关,对我帮助很大,但仍然没有解决我真正的问题。)
我知道我可以做到以下几点:
import scala.reflect.runtime.universe._
object ReflectiveMysteryA extends App {
def stupidFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
println("its a list of set of int")
case t if t =:= typeOf[Set[Long]] =>
println("its a list of set of Long")
case _ =>
println("WTF")
}
stupidFunc(List(List("a", "bc"), List("b", "def")))
stupidFunc(List(Set(1, 2), Set(2, 3, 4)))
stupidFunc(List(Set(0L, 432L), Set(321L)))
stupidFunc(List(Set("a", "bc", "def")))
// stupidFunc(Set(Set("a", "bc", "def"))) // Doesn't compile, "type mismatch"
}
// its a list of list of string
// its a list of set of int
// its a list of set of Long
// WTF
这一切都很好,我们使用TypeTag 测试类型,然后我们做相应的事情。但它只有在你真的不需要确定你测试的类型时才有效......
例如,现在我有一个像这样的函数,具有类型参数边界和一个隐式参数,用于从函数参数中从 LSB 类型“提取”类型 B:
object ReflectiveMysteryB extends App {
def specialFunc[LSB <: List[Set[_]], B: TypeTag](vv: LSB)(implicit ev: List[Set[B]] =:= LSB) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
specialFunc(List(Set(1, 2), Set(2, 3, 4)))
specialFunc(List(Set(0L, 432L), Set(321L)))
// specialFunc(List(List("a", "bc"), List("b", "def"))) // Doesn't compile, "type parameter bounds"
}
// list of set of int
// list of set of long
这也很好用。当我尝试组合这两件事时,就会出现问题:
object ReflectiveMysteryC extends App {
def stupiderFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
specialFunc(arg)
case t if t =:= typeOf[Set[Long]] =>
specialFunc(arg)
case _ =>
println("WTF")
}
def specialFunc[LSB <: List[Set[_]], B: TypeTag](vv: LSB)(implicit ev: List[Set[B]] =:= LSB) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
stupiderFunc(List(List("a", "bc"), List("b", "def")))
stupiderFunc(List(Set(1, 2), Set(2, 3, 4)))
stupiderFunc(List(Set(0L, 432L), Set(321L)))
stupiderFunc(List(Set("a", "bc", "def")))
}
不会编译
Error:(45, 7) inferred type arguments [List[A],Nothing] do not conform to method specialFunc's type parameter bounds [LSB <: List[Set[_]],B]
specialFunc(arg)
^
Error:(45, 19) type mismatch;
found : List[A]
required: LSB
specialFunc(arg)
^
Error:(45, 18) Cannot prove that List[Set[B]] =:= LSB.
specialFunc(arg)
^
Error:(47, 7) inferred type arguments [List[A],Nothing] do not conform to method specialFunc's type parameter bounds [LSB <: List[Set[_]],B]
specialFunc(arg)
^
Error:(47, 19) type mismatch;
found : List[A]
required: LSB
specialFunc(arg)
^
Error:(47, 18) Cannot prove that List[Set[B]] =:= LSB.
specialFunc(arg)
^
为了让它发挥作用,我们可以做到以下几点:
object ReflectiveMysteryD extends App {
def stupiderFunc[A: TypeTag](arg: List[A]) = typeOf[A] match {
case t if t =:= typeOf[List[String]] =>
println("its a list of list of string")
case t if t =:= typeOf[Set[Int]] =>
specialFunc(arg.asInstanceOf[List[Set[Int]]])
case t if t =:= typeOf[Set[Long]] =>
specialFunc(arg.asInstanceOf[List[Set[Long]]])
case _ =>
println("WTF")
}
def specialFunc[B: TypeTag](vv: List[Set[B]]) = {
typeOf[B] match {
case t if t =:= typeOf[Int] =>
println("list of set of int")
case t if t =:= typeOf[Long] =>
println("list of set of long")
}
}
stupiderFunc(List(List("a", "bc"), List("b", "def")))
stupiderFunc(List(Set(1, 2), Set(2, 3, 4)))
stupiderFunc(List(Set(0L, 432L), Set(321L)))
stupiderFunc(List(Set("a", "bc", "def")))
}
// its a list of list of string
// list of set of int
// list of set of long
// WTF
但现在我的问题是:如何在stupiderFunc 中匹配List[Set[_]] 的一般情况,以便将specialFunc 应用于arg,而不必列出所有特定的Int 或Long 类型?有没有办法在不修复内部类型参数的情况下使用asInstanceOf?或者有没有办法修复implicit 方法,以便在我们在match 中调用specialFunc 时发现args 实际上符合预期类型?
这是我可能使用宏来解决的问题吗?在这种情况下我应该如何处理?
【问题讨论】:
标签: scala reflection type-inference type-erasure