gpt4 book ai didi

scala - Scala 的类型删除如何用于更高种类的类型参数?

转载 作者:行者123 更新时间:2023-12-04 03:01:55 26 4
gpt4 key购买 nike

我不明白 Scala 删除哪些泛型类型参数。我曾经认为它应该删除所有泛型类型参数,但事实似乎并非如此。

如果我错了请纠正我:如果我在代码中实例化了一个 Map[Int, String] 类型的实例,那么在运行时,该实例只知道它是 Map[_, _],并且对其泛型类型参数一无所知。这就是为什么以下代码能够成功编译和执行而没有错误的原因:

val x: Map[Int, String] = Map(2 -> "a")
val y: Map[String, Int] = x.asInstanceOf[Map[String, Int]]

现在我希望所有更高种类的类型参数也被删除,也就是说,如果我有一个

class Foo[H[_, _], X, Y]

我希望 Foo[Map, Int, String] 类型的实例对 Map 一无所知。但现在考虑以下类型转换“实验”序列:

import scala.language.higherKinds

def cast1[A](a: Any): A = a.asInstanceOf[A]
def cast2[H[_, _], A, B](a: Any) = a.asInstanceOf[H[A, B]]
def cast3[F[_[_, _], _, _], H[_, _], X, Y](a: Any) = a.asInstanceOf[F[H, X, Y]]
class CastTo[H[_, _], A, B] {
def cast(x: Any): H[A, B] = x.asInstanceOf[H[A, B]]
}

ignoreException {
val v1 = cast1[String](List[Int](1, 2, 3))
// throws ClassCastException
}

ignoreException {
val v2 = cast2[Map, Int, Long](Map[String, Double]("a" -> 1.0))
// doesn't complain at all, `A` and `B` erased
}

ignoreException {
// right kind
val v3 = cast2[Map, Int, Long]((x: Int) => x.toLong)
// throws ClassCastException
}

ignoreException {
// wrong kind
val v4 = cast2[Map, Int, Long]("wrong kind")
// throws ClassCastException
}

ignoreException {
class Foo[H[_, _], X, Y](h: H[X, Y])
val x = new Foo[Function, Int, String](n => "#" * n)
val v5 = cast3[Foo, Map, Int, Long](x)
// nothing happens, happily replaces `Function` by `Map`
}

ignoreException {
val v6 = (new CastTo[Map, Int, Long]).cast(List("hello?"))
// throws ClassCastException
}

ignoreException {
val castToMap = new CastTo[Map, Int, Long]
val v7 = castToMap.cast("how can it detect this?")
// throws ClassCastException
}

ignoreException {
val castToMap = new CastTo[Map, Int, Long]
val madCast = castToMap.asInstanceOf[CastTo[Function, Float, Double]]
val v8 = madCast.cast("what does it detect at all?")
// String cannot be cast to Function???
// Why does it retain any information about `Function` here?
}


// --------------------------------------------------------------------
var ignoreBlockCounter = 0
/** Executes piece of code,
* catches an exeption (if one is thrown),
* prints number of `ignoreException`-wrapped block,
* prints name of the exception.
*/
def ignoreException[U](f: => U): Unit = {
ignoreBlockCounter += 1
try {
f
} catch {
case e: Exception =>
println("[" + ignoreBlockCounter + "]" + e)
}
}

这是输出(scala -version 2.12.4):

[1]java.lang.ClassCastException: scala.collection.immutable.$colon$colon cannot be cast to java.lang.String
[3]java.lang.ClassCastException: Main$$anon$1$$Lambda$143/1744347043 cannot be cast to scala.collection.immutable.Map
[4]java.lang.ClassCastException: java.lang.String cannot be cast to scala.collection.immutable.Map
[6]java.lang.ClassCastException: scala.collection.immutable.$colon$colon cannot be cast to scala.collection.immutable.Map
[7]java.lang.ClassCastException: java.lang.String cannot be cast to scala.collection.immutable.Map
[8]java.lang.ClassCastException: java.lang.String cannot be cast to scala.Function1
  • 情况 1、3、4 表明 asInstanceOf[Foo[...]] 确实关心 Foo,这是预期的。
  • 案例 2 表明 asInstanceOf[Foo[X,Y]] 关心XY,这也是预期的。
  • 案例 5 表明 asInstanceOf 关心更高种类的类型参数 Map,类似于案例 2,这也是预期的。

到目前为止一切顺利。然而,案例 6、7、8 表明了不同的行为:在这里,类型 CastTo[Foo, X, Y] 的实例似乎保留了关于泛型类型参数 Foo 出于某种原因。更准确地说,CastTo[Map, Int, Long] 似乎携带了足够的信息,可以知道字符串不能转换为 Map。此外,在案例 8 中,由于强制转换,它似乎甚至将 Map 更改为 Function

问题:

  1. 我的理解是否正确,CastTo 的第一个通用参数没有被删除,还是有其他我没有看到的东西?一些隐式操作或什么?
  2. 是否有描述此行为的文档?
  3. 我有什么理由想要这种行为吗?我发现它有点违反直觉,但也许只有我自己用错了工具...

感谢阅读。

编辑:在类似的例子中四处寻找发现了 2.12.4 编译器的问题(请参阅下面我自己的“答案”),但这是一个单独的问题。

最佳答案

我觉得你混淆了一些东西。

对通用类型的转换被推迟到类型变得具体的时候。例如,拿这段代码:

class CastTo[H[_, _], A, B] {
def cast(x: Any): H[A, B] = x.asInstanceOf[H[A, B]]
}

在字节码中你只能转换为一个真正的类,因为它对泛型一无所知。所以上面的内容在字节码中大致等同于:

class CastTo {
def cast(x: Object): Object = x
}

然后在代码的后面你给出一个 String方法cast并且编译器可以根据它拥有的类型信息看到,一个 Map[Int, Long]会出来的。但是在字节码中cast有一个删除的返回类型 Object ,因此编译器必须在 cast使用位置 插入强制转换方法。这段代码

val castToMap = new CastTo[Map, Int, Long]
val v7 = castToMap.cast("how can it detect this?")

将在字节码中大致等同于以下(伪)代码:

val castToMap = new CastTo
val v7 = castToMap.cast("how can it detect this?").asInstanceOf[Map]

关于您的其他问题:

  1. 不是我立即知道的。
  2. 你为什么想要它?您正在转换 StringMap[Int, Long] .那最终肯定会崩溃。使用 ClassCastException 失败(相对)快可能是最安全、对用户最友好的选择。

关于scala - Scala 的类型删除如何用于更高种类的类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48434656/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com