有人可以向我解释(或重定向到资源)为什么在这种特殊情况下,类型标签不是"正确"产生的:
class A(s: Seq[_]*)
def toto[T: TypeTag](p: Seq[T]): Seq[T] = {
println(typeTag[T].tpe)
p
}
val data = Seq( ("a", "a") )
val x = data.map(_._1)
new A(
toto(x),
toto(data.map(_._2)),
toto[String](data.map(_._2))
)
// output:
// java.lang.String
// Any
// String
据我了解,似乎我的班级A
需要"无类型" (以及存在类型)序列,然后编译器在没有明确要求时不会生成正确的类型标记(尽管它确实知道data.map(_._2)
的类型仍然使用TypeTag[Any]
...)。但它看起来很奇怪,我想知道这个现象是否有更科学的解释。
另外,即使我不想创建特殊变量(如上面的TypeTag[String]
变量),如何强制编译器生成正确的x
?
答案 0 :(得分:2)
与Scala类型推断问题一样,您需要了解预期的类型。在这种情况下,new A
的所有参数都使用预期类型Seq[_]
输入,由于协方差,它与Seq[Any]
相同。所以:
toto(data.map(_._2))
输入预期类型Seq[Any]
;输入data.map(_._2)
预期类型Seq[Any]
。 Seq#map
的签名是
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Seq[A], B, That]): That
因此根据预期类型推断出That
,并找到合适的隐式bf
。我不确定B
是推断到String
还是Any
,但它可能并不重要。
在val x = data.map(_._1)
中,没有预期的类型,因此B
被推断为String
,根据bf
找到隐式A
从B
的完整类型推断That
然后bf
。
toto(x)
输入预期类型Seq[Any]
;使用预期类型x
键入Seq[Any]
,但它已经有类型Seq[String]
,并且预期类型无关紧要。
答案 1 :(得分:1)
我想通过可能的解决方案扩展@AlexeyRomanov的答案,如何强制编译器评估特定类型:
从here我想出了强制类型差异的想法:
sealed class =!=[A,B]
trait LowerPriorityImplicits {
implicit def equal[A]: =!=[A, A] = sys.error("should not be called")
}
object =!= extends LowerPriorityImplicits {
implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] =
if (same != null) sys.error("should not be called explicitly with same type")
else new =!=[A,B]
}
现在我们可以将参数限制添加到toto
:
class A(s: Seq[_]*)
def toto[T: TypeTag](p: Seq[T])(implicit guard: T =!= Any): Seq[T] = {
println(typeTag[T].tpe)
p
}
val data = Seq(("a", "a"))
val x = data.map(_._1)
new A(
toto(x),
toto(data.map(_._2)),
toto[String](data.map(_._2))
)
输出我
java.lang.String
java.lang.String
String