我认为我已经接近开始理解类型擦除和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
测试类型,然后我们做相应的事情。但只有在你真的不需要确定你测试过的那种类型时它才有效......
例如,现在我有一个这样的函数,带有类型参数bounds和一个隐式参数,用于" extract"从函数参数类型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
但现在我的问题是:我如何匹配List[Set[_]]
中stupiderFunc
的一般情况,以便将specialFunc
应用于arg
,而无需列出所有具体内容Int
或Long
类型?有没有办法在不修复内部类型参数的情况下使用asInstanceOf
?或者有没有办法修复implicit
方法,以便在args
内调用specialFunc
时能够确定match
实际符合预期类型}?
这是一个问题,我可能会使用宏来解决?在这种情况下我该怎么办?
答案 0 :(得分:2)
这就是你想要的:
object NotAnyMoreMysteryD extends App {
def stupiderFunc[A: TypeTag, Z: TypeTag, T[_]](arg: List[A])(implicit ev: A =:= T[Z]) = typeOf[A] match {
case t if t <:< typeOf[List[_]] =>
println("its a list of list of string")
case t if t <:< typeOf[Set[_]] =>
specialFunc(arg.asInstanceOf[List[Set[Z]]])
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")))
}
替代:
def stupiderFunc[A[Z], Z: TypeTag](arg: List[A[Z]])(implicit tag: TypeTag[A[Z]]) = typeOf[A[Z]] match {
case t if t <:< typeOf[List[_]] =>
println("its a list of list of string")
case t if t <:< typeOf[Set[_]] =>
specialFunc(arg.asInstanceOf[List[Set[Z]]])
case _ =>
println("WTF")
}
结果:
scala> stupiderFunc(List(List("a", "bc"), List("b", "def")))
its a list of list of string
scala> stupiderFunc(List(Set(1, 2), Set(2, 3, 4)))
list of set of int
scala> stupiderFunc(List(Set(0L, 432L), Set(321L)))
list of set of long
scala> stupiderFunc(List(Set("a", "bc", "def")))
scala.MatchError