Scala:数组和类型擦除 [英] Scala: arrays and type erasure

查看:53
本文介绍了Scala:数组和类型擦除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写如下重载函数:

I'd like to write overloaded functions as follows:

case class A[T](t: T)
def f[T](t: T) = println("normal type")
def f[T](a: A[T]) = println("A type")

结果如我所料:

f(5)      => 普通型
f(A(5))  => A型

f(5)       => normal type
f(A(5))  => A type

到目前为止一切顺利.但问题是同样的事情不适用于数组:

So far so good. But the problem is the same thing doesn't work for Arrays:

def f[T](t: T) = println("normal type")
def f[T](a: Array[T]) = println("Array type")

现在编译器抱怨:

双重定义:方法 f:[T](t: Array[T])Unit 和方法 f:[T](t: T)Unit 在第 14 行擦除后具有相同的类型:(t: java.lang.对象)单元

double definition: method f:[T](t: Array[T])Unit and method f:[T](t: T)Unit at line 14 have same type after erasure: (t: java.lang.Object)Unit

我认为类型擦除后的第二个函数的签名应该是 (a: Array[Object])Unit 而不是 (t: Object)Unit,所以它们不应该相互冲突.我在这里错过了什么?

I think the signature of the second function after type erasure should be (a: Array[Object])Unit not (t: Object)Unit, so they shouldn't collide with each other. What am I missing here?

如果我做错了什么,写 f 的正确方法是什么,以便根据参数的类型调用正确的函数?

And if I'm doing something wrong, what would be the right way to write f's so that the right one will get called according to the type of the argument?

推荐答案

这在 Java 中从来都不是问题,因为它不支持泛型中的原始类型.因此,以下代码在 Java 中是非常合法的:

This is never an issue in Java, because it does not support primitive types in generics. Thus, following code is pretty legal in Java:

public static <T> void f(T t){out.println("normal type");}
public static <T> void f(T[] a){out.println("Array type");}

另一方面,Scala 支持所有类型的泛型.尽管 Scala 语言没有原语,但生成的字节码将它们用于 Int、Float、Char 和 Boolean 等类型.它使 Java 代码和 Scala 代码有所不同.Java 代码不接受 int[] 作为数组,因为 int 不是 java.lang.Object.所以Java可以将这些方法参数类型擦除为ObjectObject[].(这意味着 JVM 上的 Ljava/lang/Object;[Ljava/lang/Object;.)

On the other hand, Scala supports generics for all types. Although Scala language does not have primitives, the resulting bytecode uses them for types like Int, Float, Char and Boolean. It makes the difference between the Java code and Scala code. The Java code does not accept int[] as an array, because int is not an java.lang.Object. So Java can erase these method parameter types to Object and Object[]. (That means Ljava/lang/Object; and [Ljava/lang/Object; on JVM.)

另一方面,您的 Scala 代码处理所有数组,包括 Array[Int]Array[Float]Array[Char]Array[Boolean] 等.这些数组是(或可以是)原始类型的数组.它们不能在 JVM 级别转换为 Array[Object]Array[anything else].Array[Int]Array[Char] 只有一种超类型:它是 java.lang.Object.这是您可能希望拥有的更通用的超类型.

On the other hand, your Scala code handles all arrays, including Array[Int], Array[Float], Array[Char], Array[Boolean] and so on. These arrays are (or can be) arrays of primitive types. They can't be casted to Array[Object] or Array[anything else] on the JVM level. There is exactly one supertype of Array[Int] and Array[Char]: it is java.lang.Object. It is more general supertype that you may wish to have.

为了支持这些语句,我编写了一个使用不太通用的方法 f 的代码:

To support these statements, I've written a code with less generic method f:

def f[T](t: T) = println("normal type")
def f[T <: AnyRef](a: Array[T]) = println("Array type")

此变体的工作方式类似于 Java 代码.这意味着,不支持原语数组.但是这个小小的改变足以让它编译.另一方面,由于类型擦除原因,无法编译以下代码:

This variant works like the Java code. That means, array of primitives aren't supported. But this small change is enough to get it compiled. On the other hand, following code can't be compiled for the type erasure reason:

def f[T](t: T) = println("normal type")
def f[T <: AnyVal](a: Array[T]) = println("Array type")

添加@specialized并不能解决问题,因为生成了泛型方法:

Adding @specialized does not solve the problem, because a generic method is generated:

def f[T](t: T) = println("normal type")
def f[@specialized T <: AnyVal](a: Array[T]) = println("Array type")

我希望@specialized 可能已经解决了这个问题(在某些情况下),但编译器目前不支持它.但我不认为这会是 scalac 的高优先级增强.

I hope that @specialized might have solved the problem (in some cases), but compiler does not support it at the moment. But I don't think that it would be a high priority enhancement of scalac.

这篇关于Scala:数组和类型擦除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆