“扩展测试”和“扩展测试[T]”之间的区别是完全相同的吗?

时间:2014-05-12 08:17:17

标签: scala

我编译以下代码,最后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]

1 个答案:

答案 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]]