- 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/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!