scala雾中风景(14): trait的泛型参数为何不支持context bounds

回答一个网友的问题:为什么定义一个trait时无法对其泛型参数声明为context boundsview bounds,而class可以? 当然可以在方法层面使用context bounds而绕过这个限制,但不理解为何trait会与class在这个问题上存在差异。

scala> import scala.reflect.runtime.universe.TypeTag

scala> trait My[T:TypeTag] {}
<console>:1: error: traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'

关于context boundsview bounds的感念可以参考以前的这篇这篇

其实自己google一下就可以看到martin odersky对这个问题的回答,他解释这个是因为trait是没有构造参数的,而泛型参数使用context boundsview bounds在背后是靠编译器把隐式参数做为一个私有成员让整个类都可以访问,并在构造方法上限制了这个上下文必须存在这个隐式参数。未来也会考虑在trait上支持context boundsview bounds,但还没有具体的规划。

先看看class泛型参数在context bound的背后实现:

$ scala -Xprint:typer -e 'import scala.reflect.runtime.universe._; class My[T:TypeTag]'
    ...

    import scala.reflect.runtime.`package`.universe._;
    class My[T] extends scala.AnyRef {
      implicit <synthetic> <paramaccessor> private[this] val evidence$1: reflect.runtime.universe.TypeTag[T] = _;
      def <init>()(implicit evidence$1: reflect.runtime.universe.TypeTag[T]): this.My[T] = {
        My.super.<init>();
        ()
      }
    }
    ...

再看看view bound的背后实现:

$ scala -Xprint:typer -e 'class  My[T <% java.io.Closeable]'
    ...

    class My[T] extends scala.AnyRef {
      implicit <synthetic> <paramaccessor> private[this] val evidence$1: T => java.io.Closeable = _;
      def <init>()(implicit evidence$1: T => java.io.Closeable): this.My[T] = {
        My.super.<init>();
        ()
      }
    }
    ...

简单的说,是因为当前采用的底层实现方式限制了trait还不能支持类型参数的context boundsview bounds

想要达到目的的话,只能在每个方法层面声明:

scala> trait A { def foo[T:TypeTag](t:T):Unit }
defined trait A

Leave a Reply

Your email address will not be published. Required fields are marked *