我编译以下代码,最后2行都成功编译。但他们之间有什么不同吗?
import scala.reflect.{classTag, ClassTag}
abstract class Test[T:ClassTag];
class Test_1[T:ClassTag] extends Test
class Test_1[T:ClassTag] extends Test[T]
答案 0 :(得分:2)
这很棘手。
The spec说:
方法或非特质类的类型参数A也可以有一个或 更多上下文边界A:T。在这种情况下,类型参数可以是 实例化为任何类型S,其中存在证据 实例化点S满足约束T.这样的证据 由一个类型为T [S]的隐式值组成。
在这种情况下,证据由子类上绑定的上下文提供。
因此编译器推断出与子类相同的类型arg。
你可以这样检查一下。
显然,res4
不是Tag[Nothing]
。但这只是报告提供给超类构造函数的隐式证据,它是来自Tag[T]
的隐式Test_1
。
scala> abstract class Test[T:ClassTag] { def f = implicitly[ClassTag[T]] }
defined class Test
scala> class Test_1[T:ClassTag] extends Test { def g = implicitly[ClassTag[T]] }
defined class Test_1
scala> new Test_1().f
res2: scala.reflect.ClassTag[Nothing] = Nothing
scala> new Test_1().g
res3: scala.reflect.ClassTag[Nothing] = Nothing
scala> new Test_1[Thread]().f
res4: scala.reflect.ClassTag[Thread] = java.lang.Thread
scala> new Test_1[Thread]().g
res5: scala.reflect.ClassTag[Thread] = java.lang.Thread
没什么了不起的,只是显示Nothing
显式改变res8
的结果。
scala> class Test2[T:ClassTag] extends Test[Nothing] { def g = implicitly[ClassTag[T]] }
defined class Test2
scala> new Test2().f
res6: scala.reflect.ClassTag[Nothing] = Nothing
scala> new Test2().g
res7: scala.reflect.ClassTag[Nothing] = Nothing
scala> new Test2[Thread]().f
res8: scala.reflect.ClassTag[Nothing] = Nothing
scala> new Test2[Thread]().g
res9: scala.reflect.ClassTag[Thread] = java.lang.Thread
它不适用于两个类型参数:
scala> abstract class Test[T:TypeTag, U: TypeTag] { def f = (implicitly[TypeTag[T]],implicitly[TypeTag[U]]) }
defined class Test
scala> class Test1[X: TypeTag, Y: TypeTag] extends Test { def g = implicitly[TypeTag[X]] }
<console>:11: error: ambiguous implicit values:
both value evidence$2 of type reflect.runtime.universe.TypeTag[Y]
and value evidence$1 of type reflect.runtime.universe.TypeTag[X]
match expected type reflect.runtime.universe.TypeTag[T]
class Test1[X: TypeTag, Y: TypeTag] extends Test { def g = implicitly[TypeTag[X]] }
^
另一种观点:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> abstract class Top[A: TypeTag] { def f = implicitly[TypeTag[A]] }
defined class Top
scala> class Bot[B: TypeTag] extends Top { def g = implicitly[TypeTag[B]] }
defined class Bot
scala> new Bot[String]().f
res1: reflect.runtime.universe.TypeTag[String] = TypeTag[String]
scala> new Bot[String]().g
res2: reflect.runtime.universe.TypeTag[String] = TypeTag[String]
scala> class Not[B: TypeTag] extends Top[Nothing] { def g = implicitly[TypeTag[B]] }
defined class Not
scala> new Not[String]().f
res3: reflect.runtime.universe.TypeTag[Nothing] = TypeTag[Nothing]
scala> new Not[String]().g
res4: reflect.runtime.universe.TypeTag[String] = TypeTag[String]
或者,更简单地显示类型推断:
scala> class Knot[A: TypeTag] { def f = implicitly[TypeTag[A]] }
defined class Knot
scala> def f = { implicit val x = typeTag[Top[String]] ; val k = new Knot ; k.f }
f: reflect.runtime.universe.TypeTag[Top[String]]