- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我不明白 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
asInstanceOf[Foo[...]]
确实关心 Foo
,这是预期的。asInstanceOf[Foo[X,Y]]
不关心X
和Y
,这也是预期的。asInstanceOf
不关心更高种类的类型参数 Map
,类似于案例 2,这也是预期的。 到目前为止一切顺利。然而,案例 6、7、8 表明了不同的行为:在这里,类型 CastTo[Foo, X, Y]
的实例似乎保留了关于泛型类型参数 Foo
出于某种原因。更准确地说,
CastTo[Map, Int, Long]
似乎携带了足够的信息,可以知道字符串不能转换为 Map
。此外,在案例 8 中,由于强制转换,它似乎甚至将 Map
更改为 Function
。
问题:
我的理解是否正确,CastTo
的第一个通用参数没有被删除,还是有其他我没有看到的东西?一些隐式操作或什么?
是否有描述此行为的文档?
我有什么理由想要这种行为吗?我发现它有点违反直觉,但也许只有我自己用错了工具...
感谢阅读。
编辑:在类似的例子中四处寻找发现了 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]
关于您的其他问题:
- 不是我立即知道的。
- 你为什么不想要它?您正在转换
String
到 Map[Int, Long]
.那最终肯定会崩溃。使用 ClassCastException
失败(相对)快可能是最安全、对用户最友好的选择。
关于scala - Scala 的类型删除如何用于更高种类的类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48434656/
我有一些 Scala 代码,它用两个不同版本的类型参数化函数做了一些漂亮的事情。我已经从我的应用程序中简化了很多,但最后我的代码充满了形式 w(f[Int],f[Double]) 的调用。哪里w()是
如果我在同一目录中有两个单独的未编译的 scala 文件: // hello.scala object hello { def world() = println("hello world") }
val schema = df.schema val x = df.flatMap(r => (0 until schema.length).map { idx => ((idx, r.g
环境: Play 2.3.0/Scala 2.11.1/IntelliJ 13.1 我使用 Typesafe Activator 1.2.1 用 Scala 2.11.1 创建一个新项目。项目创建好后
我只是想知道如何使用我自己的类扩展 Scala 控制台和“脚本”运行程序,以便我可以通过使用实际的 Scala 语言与其通信来实际使用我的代码?我应将 jar 放在哪里,以便无需临时配置即可从每个 S
我已经根据 README.md 文件安装了 ensime,但是,我在低级 ensime-server 缓冲区中出现以下错误: 信息: fatal error :scala.tools.nsc.Miss
我正在阅读《Scala 编程》一书。在书中,它说“一个函数文字被编译成一个类,当在运行时实例化时它是一个函数值”。并且它提到“函数值是对象,因此您可以根据需要将它们存储在变量中”。 所以我尝试检查函数
我有 hello world scala native 应用程序,想对此应用程序运行小型 scala 测试我使用通常的测试命令,但它抛出异常: NativeMain.scala object Nati
有few resources在网络上,在编写与代码模式匹配的 Scala 编译器插件方面很有指导意义,但这些对生成代码(构建符号树)没有帮助。我应该从哪里开始弄清楚如何做到这一点? (如果有比手动构建
我是 Scala 的新手。但是,我用 创建了一个中等大小的程序。斯卡拉 2.9.0 .现在我想使用一个仅适用于 的开源库斯卡拉 2.7.7 . 是吗可能 在我的 Scala 2.9.0 程序中使用这个
有没有办法在 Scala 2.11 中使用 scala-pickling? 我在 sonatype 存储库中尝试了唯一的 scala-pickling_2.11 工件,但它似乎不起作用。我收到消息:
这与命令行编译器选项无关。如何以编程方式获取代码内的 Scala 版本? 或者,Eclipse Scala 插件 v2 在哪里存储 scalac 的路径? 最佳答案 这无需访问 scala-compi
我正在阅读《Scala 编程》一书,并在第 6 章中的类 Rational 实现中遇到了一些问题。 这是我的 Rational 类的初始版本(基于本书) class Rational(numerato
我是 Scala 新手,我正在尝试开发一个使用自定义库的小项目。我在库内创建了一个mysql连接池。这是我的库的build.sbt organization := "com.learn" name :
我正在尝试运行一些 Scala 代码,只是暂时打印出“Hello”,但我希望在 SBT 项目中编译 Scala 代码之前运行 Scala 代码。我发现在 build.sbt 中有以下工作。 compi
Here链接到 maven Scala 插件使用。但没有提到它使用的究竟是什么 Scala 版本。我创建了具有以下配置的 Maven Scala 项目: org.scala-tools
我对 Scala 还很陌生,请多多包涵。我有一堆包裹在一个大数组中的 future 。 future 已经完成了查看几 TB 数据的辛勤工作,在我的应用程序结束时,我想总结上述 future 的所有结
我有一个 scala 宏,它依赖于通过包含其位置的静态字符串指定的任意 xml 文件。 def myMacro(path: String) = macro myMacroImpl def myMacr
这是我的功能: def sumOfSquaresOfOdd(in: Seq[Int]): Int = { in.filter(_%2==1).map(_*_).reduce(_+_) } 为什么我
这个问题在这里已经有了答案: Calculating the difference between two Java date instances (45 个答案) 关闭 5 年前。 所以我有一个这
我是一名优秀的程序员,十分优秀!