scala - 为什么 Scala "handle"ClassTags 不自动?

标签 scala reflection

类标签似乎真的很容易使用,然而,在数学上总是可靠地自动插入 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/

相关文章:

java - 在运行时修改类中的字段 - java

scala - Spark结构化流中的外连接两个数据集(不是DataFrame)

arrays - 如何将 "map"数组转换为单个新对象?

c# - 在使用默认方法实现接口(interface)的类上使用 `GetMethod` 返回 null

Java 反射 : How to get methods with no parameters only

c# - 反射 PropertyInfo.GetValue 来自集合

scala - Scalaz 中的 Future[List[Option[List[Double]]] 到 Future[Option[List[List[Double]]]

scala - 通过折叠将 Char 列表连接成字符串

scala - 为什么添加 import `import cats.instances.future._` 会导致隐式 Functor[Future] 编译错误

从另一个类调用 protected 方法的测试方法