类标签似乎真的很容易使用,然而,在数学上总是可靠地自动插入 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)
...
}
...并自动将后者转换为前者?
是否有技术原因,例如编译器/反射库不能总是可靠地确定类标签的可取性?或者保持这种明确性纯粹是一种有意识的设计选择?例如,鼓励程序员首先避免使用类标签以获得更简洁的设计和更好的性能,即使知道在许多情况下这是不可能的?
附言我不是在问为什么 Scala 不(也不建议它应该)添加
ClassTag
具有泛型类型参数的每个方法定义的魔法;我只是在问为什么在需要/不可避免时不能自动完成。
最佳答案
此语法:
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 支持具体泛型,一切都会不同......
关于scala - 为什么 Scala "handle"ClassTags 不自动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21683420/