回答一个网友的问题:为什么定义一个trait
时无法对其泛型参数声明为context bounds
或view 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 bounds
和view bounds
的感念可以参考以前的这篇 和 这篇
其实自己google一下就可以看到martin odersky对这个问题的回答,他解释这个是因为trait
是没有构造参数的,而泛型参数使用context bounds
和view bounds
在背后是靠编译器把隐式参数做为一个私有成员让整个类都可以访问,并在构造方法上限制了这个上下文必须存在这个隐式参数。未来也会考虑在trait
上支持context bounds
和view 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 bounds
和view bounds
。
想要达到目的的话,只能在每个方法层面声明:
scala> trait A { def foo[T:TypeTag](t:T):Unit }
defined trait A