Scala 2.11.8类型标记并非总是由编译器正确生成
有人能向我解释一下(或重定向到参考资料)为什么在这种特殊情况下,类型标记没有“正确”生成:Scala 2.11.8类型标记并非总是由编译器正确生成,scala,Scala,有人能向我解释一下(或重定向到参考资料)为什么在这种特殊情况下,类型标记没有“正确”生成: 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[Strin
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(u.\u 2)
的类型,它仍然使用TypeTag[Any]
…)。但这看起来很奇怪,我想知道是否有更科学的解释来解释这一现象
另外,即使我不想创建特殊变量(如上面的
x
变量),我如何强制编译器生成正确的TypeTag[String]
!我有一个解释,但我不确定它是否正确(比如说80%)
与Scala类型推断问题一样,您需要了解预期的类型。在这种情况下,new A
的所有参数都使用预期的类型Seq[\u]
,由于协方差的原因,这与Seq[Any]
相同。因此:
toto(data.map(u._2))
是按预期类型键入的Seq[Any]
<代码>数据。映射(u._2)是按预期类型键入的Seq[Any]
。Seq#map
的签名为
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Seq[A], B, That]): That
因此,根据预期类型推断出,并找到合适的隐式bf
。实际上,我不确定B
是否被推断为String
或Any
,但这可能并不重要
val x=data.map(u.\u 1)
中,没有预期的类型,因此B
被推断为字符串
,根据A
和B
找到隐式bf
,然后从bf
的完整类型推断出
toto(x)
是按预期类型键入的Seq[Any]
x
是使用预期的类型Seq[Any]
键入的,但它已经有了类型Seq[String]
,预期的类型并不重要我想通过可能的解决方案来扩展@AlexeyRomanov的答案,即如何强制编译器计算特定类型: 根据我的想法,强制类型差异:
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
toto[String](data.map(u.2))
强制它使用TypeTag[String]
。顺便说一句:在2.12.4中也发生了同样的情况。是的,它确实发生了,尽管在编译器知道信息的情况下指定它有点奇怪……很好的答案,不幸的是,如果我们确实需要Any
,例如使用toto(Seq(“1”,2))
,它会失败(在编译时)。我不想把<代码>任何< /代码>看作一个显式的错误,只是当它不是预期的类型时避免它。我会尝试使用你的代码,看看我是否能用它解决一些问题。Thanks@Vince.BdnWith=!=我破坏了任何预期类型检查的正确性。我不确定,您是否可以通过泛化函数来解决它(使用Any确定的情况将强制转换为Any
,而不是具体的类)。但是有了一个类的限制,您就可以为这个特定的案例引入唯一的附加方法,而不是在一堆案例中遇到问题。但是如果您能找到泛化的解决方案,我会很高兴的。谢谢,这确实是有意义的,但是我不太明白为什么它在使用data.map(u.\u 2.asInstanceOf[String])
时也会失败。在这种情况下,。\u 2
是用(String,String)=>String
强制输入的。所以它应该回到你的2。解释一下,不是吗?因为键入是显式的,预期的类型可能会被忘记?我想这可能是因为您确实有两个参数,第二个参数是隐式的TypeTag[Class]
,其中Class
是基于预期的Any
解析的。因此,以后对基于map
inners的Seq
类型的评估不会影响整个类型T
更重要的是map
有两个类型参数。我已经编辑了答案。(虽然.\u 2.asInstanceOf[String]
不应该按照以前的版本工作,(\u 2):((String,String))=>String
应该而且仍然不应该。)