Scala如何将类型转换为通用类型

4

我对泛型感到困惑。我期望2.asInstanceOf[A]会被转换为类型A,但它实际上被转换为Int。 此外,输入是java.lang.Long,而输出是一个Int列表(根据定义,输入和输出应该是相同的类型)。这是为什么?

def whatever[A](x: A): List[A] = {
  val two = 2.asInstanceOf[A]
  val l = List(1.asInstanceOf[A],2.asInstanceOf[A])

  println(f"Input type inside the function for 15L: ${x.getClass}")
  println(f"The class of two: ${two.getClass}, the value of two: $two")
  println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
  l
}

println(f"Returned from whatever function: ${whatever(15L)}")

输出:

Input type inside the function for 15L: class java.lang.Long
The class of two: class java.lang.Integer, the value of two: 2
The class of the first element of l: class java.lang.Integer, first element value: 1
Returned from whatever function: List(1, 2)
3个回答

16

a.asInstanceOf[B]的意思是:

亲爱的编译器;

请忘记你认为的a的类型。我知道得更好。我知道如果a不是实际的类型B,那么我的程序可能会崩溃,但我非常聪明,这不会发生。

真诚的,超级程序员

换句话说,val b:B = a.asInstanceOf[B] 不会创建一个新的类型为B的变量,它将创建一个新的变量,被视为类型B。如果a的实际底层类型与类型B兼容,则一切正常。如果a的实际类型与B不兼容,则会出现问题。


4
这种回答让我希望我有超过一个投票权 :) - Tim
1
一起来升级!对于这样一个有趣的方法,作为答案。 - Nathan

3

类型擦除。为了进行类型检查,将2强制转换为A;但在后续的编译阶段,A被擦除为Object,因此您的代码变成了等效于

def whatever(x: Object): List[Object] = {
  val two = 2.asInstanceOf[Object]
  val l = List(1.asInstanceOf[Object],2.asInstanceOf[Object])

  println(f"Input type inside the function for 15L: ${x.getClass}")
  println(f"The class of two: ${two.getClass}, the value of two: $two")
  println(f"The class of the first element of l: ${l.head.getClass}, first element value: ${l.head}")
  l
}

2.asInstanceOf[Object]是一个装箱操作,返回一个java.lang.Integer

如果您尝试将返回值实际用作List[Long],最终会出现ClassCastException,例如:

val list = whatever(15L)
val x = list(0)

x将被推断为Long,并插入一个转换以取消装箱预期的java.lang.Long


1

@jwvh的答案很到位。在这里,我只会添加一种解决方案,以防您想要在whatever中安全地将Int转换为A的问题,而不知道A是什么。当然,只有在提供了一种从Int构建特定A的方法时,才有可能做到这一点。我们可以使用类型类来实现:

trait BuildableFromInt[+A] {
  def fromInt(i: Int): A
}

现在,您只需要为任何想在whatever中使用的类型A隐式提供BuildableFromInt即可:
object BuildableFromInt {
    implicit val longFromInt: BuildableFromInt[Long] = Long.box(_)
}

现在定义只接受符合类型A的任何内容:

def whatever[A : BuildableFromInt](x: A): List[A] = {
  val two = implicitly[BuildableFromInt[A]].fromInt(2)
  // Use two like any other "A"
  // ...
}

现在,任何可以使用 BuildableFromInt 的类型都可以使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接