在Scala中,所有抽象类型在擦除后具有相同的类型。

7 浏览
0 Comments

在Scala中,所有抽象类型在擦除后具有相同的类型。

以下代码无法编译,因为两个乘法操作符在类型擦除后具有相同的类型(f: Object)Object。我了解类型擦除,但是我看到的所有情况都会擦除泛型类型,例如List[Int]List[String],正如在Scala double definition (2 methods have the same type erasure)中所回答的那样。我该如何让Scala将不同类型的XxxT类型区分开来?

trait AbstractTypes {
  type ScalarT
  type VectorT
  abstract class Operators(u: VectorT) {
    def *(f: ScalarT): VectorT
    def *(v: VectorT): VectorT
  }
}

0
0 Comments

在Scala中,所有的抽象类型在擦除之后具有相同的类型。这意味着,无论抽象类型的具体实现是什么,它们在运行时都会被擦除为相同的类型。

上面给出的代码展示了一个使用抽象类型的示例。在这个示例中,有一个抽象类型`ScalarT`和`VectorT`,并且定义了一个抽象类`Operators`,它接受一个`VectorT`类型的参数`u`。`Operators`类中有两个方法`*`,一个接受一个`ScalarT`类型的参数`f`,另一个接受一个`VectorT`类型的参数`v`。在第二个方法中,使用了`DummyImplicit`来解决擦除导致参数类型相同的问题。

`DummyImplicit`是一个特殊的隐式值,它不会被实际使用,只是为了在编译时提供一个类型,以解决擦除后参数类型相同的问题。如果需要更多的方法重载,并且它们的擦除结果是相同的类型,可以使用多个`DummyImplicit`。

在上述示例中,通过使用`DummyImplicit`作为第二个方法的隐式参数,可以实现方法重载,即使在擦除之后参数类型相同。

总结起来,Scala中抽象类型在擦除之后会具有相同的类型,为了解决擦除导致的参数类型相同的问题,可以使用`DummyImplicit`来提供类型,并实现方法的重载。这样,即使在擦除之后,方法的参数类型仍然是不同的。

0
0 Comments

在Scala中,所有的抽象类型在擦除之后都具有相同的类型。上述代码中使用了一个技巧,通过将参数声明为按名称调用的方式来定义第二个方法:

trait AbstractTypes {
  type ScalarT
  type VectorT
  abstract class Operators(u: VectorT) {
    def *(f: ScalarT): VectorT
    def *(v: => VectorT): VectorT
  }
}
object ConcreteTypes extends AbstractTypes {
  type ScalarT = Double
  type VectorT = Seq[Double]
  class ConcreteOperators(u: Seq[Double]) extends Operators(u) {
    def *(f: Double): Seq[Double] = u.map(_ * f)
    def *(v: => Seq[Double]): Seq[Double] = 
      (u zip v).map { case (a, b) => a * b }
  }
}
new ConcreteTypes.ConcreteOperators(Seq(2.0, 3.0, 5.0)) * 7.0 
Seq[Double] = List(14.0, 21.0, 35.0)
new ConcreteTypes.ConcreteOperators(Seq(2.0, 3.0, 5.0)) * Seq(1.0, 2.0, 3.0) 
Seq[Double] = List(2.0, 6.0, 15.0)

这是一个有趣的技巧,但它稍微改变了语义。当您使用函数而不是值时,例如,每次使用都会再次调用该函数。

问题的出现原因是,当我们使用抽象类型VectorT时,它在擦除之后被擦除为Seq[Double]。因此,当我们在Operators类中定义一个接受VectorT类型参数的方法时,实际上它接受的是Seq[Double]类型参数。这导致在调用该方法时可能会出现类型不匹配的问题。

解决方法是使用类型参数而不是抽象类型。通过将VectorT类型参数化为T,我们可以确保在擦除之后仍然具有正确的类型。修改后的代码如下:

trait AbstractTypes[T] {
  type ScalarT
  abstract class Operators(u: T) {
    def *(f: ScalarT): T
    def *(v: => T): T
  }
}
object ConcreteTypes extends AbstractTypes[Seq[Double]] {
  type ScalarT = Double
  class ConcreteOperators(u: Seq[Double]) extends Operators(u) {
    def *(f: Double): Seq[Double] = u.map(_ * f)
    def *(v: => Seq[Double]): Seq[Double] = 
      (u zip v).map { case (a, b) => a * b }
  }
}
new ConcreteTypes.ConcreteOperators(Seq(2.0, 3.0, 5.0)) * 7.0 
Seq[Double] = List(14.0, 21.0, 35.0)
new ConcreteTypes.ConcreteOperators(Seq(2.0, 3.0, 5.0)) * Seq(1.0, 2.0, 3.0) 
Seq[Double] = List(2.0, 6.0, 15.0)

通过使用类型参数,我们可以确保在擦除之后仍然具有正确的类型,并且不会出现类型不匹配的问题。

0