类标记似乎非常容易使用,但是,在数学上是否可以始终可靠地自动插入ClassTag
样板至少在某些情况下(如果不是全部的话)?考虑这个例子:
def foo[T: ClassTag] = {
val cls = classTag[T].runtimeClass.asInstanceOf[Class[T]]
val myList: Seq[T] = parseList(rawJson, cls) // let's assume parseList a library method that needs to work with a Class instance (e.g. RestFB's fetchConnnection)
...
}
为什么Scala不会让我改写:
def foo[T] = {
val cls = classOf[T]
val myList: Seq[T] = parseList(rawJson, cls) // let's assume parseList a library method that needs to work with a Class instance (e.g. RestFB's fetchConnnection)
...
}
...并自动将后者转换为前者?
是否有技术原因,例如编译器/反射库并不总能可靠地确定类标签的可取性?或者纯粹是一种有意识的设计选择来保持这一点?例如,鼓励程序员首先避免使用类标签以获得更清洁的设计和更好的性能,即使已知在许多情况下它是不可能的?
PS 我不问为什么Scala没有(也不建议应该)将ClassTag
魔法添加到每个带有泛型类型参数的方法定义;我只是问为什么当需要/不可避免时它无法自动完成。
答案 0 :(得分:4)
此语法:
def foo[T: ClassTag] = ...
实际上是这个的简写:
def foo[T](implicit ev: ClassTag[T]) = ...
这意味着如果为每个泛型类型参数提供ClassTag[T]
,那么每个函数都会有额外的隐藏参数,甚至几个。
这当然是完全不受欢迎的。这种方法最突出的缺点之一是使用泛型时几乎破坏了Java的互操作性:
SomeClass someClass = new SomeClass();
someClass.foo<Integer>(ClassTag.apply(Integer.class));
想象一下更高级的通用方法和参数。这只是为了能够匹配泛型类型,这几乎是不需要的。
调用Java泛型方法也是不明智的。这里应该调用哪种方法:
val jc = new JavaClass
jc.foo[Int]()
如果JavaClass
定义如下:
public class JavaClass {
public <T> void foo() { ... }
public <T> void foo(ClassTag<T> ct) { ... }
}
当然,如果Java支持reified generics,一切都会有所不同......