Scala:没有明确已知类型参数的类型转换

2024-03-26

考虑以下示例:

case class C[T](x:T) {
  def f(t:T) = println(t)
  type ValueType = T
}

val list = List(1 -> C(2), "hello" -> C("goodbye"))

for ((a,b) <- list) {
  b.f(a)
}

在这个例子中,我知道(运行时保证)类型a将会有一些T, and b将有类型C[T]与相同的T。当然,编译器无法知道这一点,因此我们会得到一个输入错误b.f(a).

为了告诉编译器这个调用没问题,我们需要进行类型转换b.f(a.asInstanceOf[T])。很遗憾,T这里不知道。所以我的问题是:我该如何重写b.f(a)为了使这段代码编译?

我正在寻找一种不涉及复杂结构(以保持代码可读)的解决方案,并且这是“干净的”,因为我们不应该依赖代码擦除来使其工作(请参阅下面的第一种方法)。

我有一些工作方法,但由于种种原因,我发现它们并不令人满意。

我尝试过的方法:

b.asInstanceOf[C[Any]].f(a)

这是可行的,并且具有合理的可读性,但它是基于“谎言”。b不属于类型C[Any],我们没有收到运行时错误的唯一原因是我们依赖 JVM 的限制(类型擦除)。我认为这是很好的风格,仅供使用x.asInstanceOf[X]当我们知道这一点时x确实是类型X.

  b.f(a.asInstanceOf[b.ValueType])

根据我对类型系统的理解,这应该有效。我已添加会员ValueType到班级C为了能够显式引用类型参数T。然而,在这种方法中,我们收到一条神秘的错误消息:

Error:(9, 22) type mismatch;
 found   : b.ValueType
    (which expands to)  _1
 required: _1
  b.f(a.asInstanceOf[b.ValueType])
                    ^

为什么?它似乎在抱怨我们期望类型_1但有类型_1! (但即使这种方法有效,也仅限于我们有可能添加成员的情况ValueType to C. If C是一些现有的库类,我们也不能这样做。)

for ((a,b) <- list.asInstanceOf[List[(T,C[T]) forSome {type T}]]) {
  b.f(a)
}

这个有效,并且在语义上是正确的(即,我们在调用时不会“撒谎”asInstanceOf)。局限性在于这有点不可读。此外,它在某种程度上是针对当前情况的:如果a,b不是来自同一个迭代器,那么我们可以在哪里应用这种类型转换呢? (此代码还具有对于 Intelli/J IDEA 2016.2 来说过于复杂的副作用,它在编辑器中将其突出显示为错误。)

  val (a2,b2) = (a,b).asInstanceOf[(T,C[T]) forSome {type T}]
  b2.f(a2)

我本来希望这个能发挥作用a2,b2现在应该有类型T and C[T]为了同样的存在T。但是我们得到一个编译错误:

Error:(10, 9) type mismatch;
 found   : a2.type (with underlying type Any)
 required: T
  b2.f(a2)
       ^

为什么? (除此之外,该方法的缺点是由于一对的创建和销毁而产生运行时成本(我认为)。)

  b match {
    case b : C[t] => b.f(a.asInstanceOf[t])
  }

这有效。但是用匹配项括住代码会使代码的可读性大大降低。 (而且对于 Intelli/J 来说也太复杂了。)


在我看来,最干净的解决方案是您通过类型捕获模式匹配找到的解决方案。您可以通过将模式直接集成到您的理解中来使其简洁,并希望具有可读性,如下所示:

for ((a, b: C[t]) <- list) {
  b.f(a.asInstanceOf[t])
}

Fiddle: http://www.scala-js-fiddle.com/gist/b9030033133ee94e8c18ad772f3461a0 http://www.scala-js-fiddle.com/gist/b9030033133ee94e8c18ad772f3461a0

如果您还没有处于 for 理解状态,不幸的是相应的模式分配不起作用:

val (c, d: C[t]) = (a, b)
d.f(c.asInstanceOf[t])

那是因为t不再在第二行的范围内。在这种情况下,您将必须使用完整的模式匹配。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala:没有明确已知类型参数的类型转换 的相关文章

随机推荐

  • 迅捷继承:超级的超级

    假设这三个类具有简单的层次结构 class A func foo print A class B A override func foo super foo print B class C B override func foo print
  • 使用迭代器初始化字符串,出现“转置指针范围”异常

    也许是一个菜鸟问题 但为什么是这两行 vector
  • 将方法列表中的方法应用于 pandas 数据框

    这是我的第一个问题 所以请耐心等待 我的问题如下 假设我们有一个 pandas Dataframe 并且我们希望动态地将一些 pd Series 方法应用于该 Dataframe 的一组列 为什么下面的例子不起作用 testframe pd
  • Jenkinsfile 中的 Anaconda

    由于我们运行的测试越来越长 我认为从 Travis CI 切换到 Jenkins 在我的本地计算机上 是个好主意 设置 Jenkins 相对简单 但让我的 Jenkinsfile 工作 却不是那么简单 我正在尝试下载 miniconda g
  • 基于存储过程参数的条件 where 子句?

    我有一个带有参数的 SQL Server 2005 存储过程 includeClosedProjects 有一个WHERE我想根据这个参数控制的子句 create proc sel projects incClosedRel int 1 a
  • Sublime Text 2 Javascript 控制台

    我是 Sublime Text2 和 Javascript 新手 使用 Windows 8 我正在尝试在 Sublime Text 中创建一个 Javascript 控制台 我尝试了两种方法 但没有一个对我有用 方法一 我已经安装了在这里找
  • 如何在 android 中从 Http 或 RTSP Url 流式传输视频

    我想在 android 上播放 Http 和 Rtsp 的视频 目前我正在尝试使用 http 链接 但是当我的活动开始时 它只是开始播放带有空白黑屏的音频 没有视频显示 我在下面发布了我的代码 感谢您提前提供的任何帮助 如果有人可以提供一个
  • 检测字节顺序

    我目前正在尝试创建一个C无论目标系统的字节顺序如何 源代码都能正确处理 I O 我选择了 little endian 作为我的 I O 约定 这意味着 对于 big endian CPU 我需要在写入或读取时转换数据 转换不是问题 我面临的
  • C++ TR2 文件系统库的状态如何?

    截至上次布里斯托尔会议 C TR2 文件系统库的状态如何 它将成为 C 1Y C 14 的一部分 还是暂停 或者最近三次会议有任何已知的评论吗 It has 最近获得ISO委员会一致批准 http article gmane org gma
  • Ember 数据:已加载数据哈希...但未提供主键“未定义”

    我正在尝试使用 Ember Data 来加载模型 获取模型的 AJAX 调用似乎成功 但我得到以下信息 Uncaught Error assertion failed A data hash was loaded for a model o
  • 该元素导致 Firefox 中的元素溢出

    我不使用 Bootstrap 或 reset css reboot css 我正在尝试使用通用 css 构建一个网站 我正在做非常基本的事情 但我到处都得到 这个元素导致元素溢出 我已经有一段时间没有在没有任何 css 框架的情况下完成布局
  • C 中的字符串和指针

    include
  • 未检测到 Flash 10:世界上最普遍的网络视频错误?

    问题如下 确保您对网站上 Flash 版本 x 的要求能够正确检测到更高版本的 Adob e Flash Player 版本 10 或 1y 的存在的最佳方法是什么 现在谜团来了 为什么这么多需要 Flash Player 版本 8 和 9
  • 01 背包专业化

    抱歉 如果这个问题已经得到解答 但我对算法没有深入的了解 并且并不总是注意到算法不同专业之间的微妙之处 我有 我认为是 01 背包问题的一个轻微变体 我有一个背包 其最大重量为 W 有 N 个重量为 w 价值为 v 的物品可供选择 我想要做
  • 为什么 Arc::try_unwrap() 会导致恐慌?

    我正在编写一个简单的聊天服务器 它向所有连接的客户端广播消息 由于我是初学者 代码可能看起来很糟糕 对等点尚未在任何地方使用 因为我想将其传递给handle client函数也是如此 因此当数据在流中可用并成功读取时 我想在所有连接的客户端
  • 为每个对象 JointJS 创建一个 ToolElement

    我试图为每个对象创建一种工具菜单 当您单击或将鼠标悬停在某个元素上时 它会显示可以执行的几个操作 删除 旋转 放大 链接等 我用过这个question https stackoverflow com questions 30153345 h
  • iOS CoreData批量插入?

    在我的 iPhone 应用程序中 我需要将大约 2000 条记录插入 Core Data 然后用户才能使用该应用程序的任何功能 我正在将记录从本地 JSON 文件加载到 CoreData 中 此过程需要很长时间 2 5 分钟以上 但只需要发
  • 当用户在 Chrome 上按下键盘时,如何检测“删除”和“.”?

    当我按下 它触发了三个事件 keydown keypress and keyup keydown which 190 keyCode 190 keypress which 46 keyCode 46 keyup which 190 keyC
  • AWS Lambda:在运行时获取当前重试尝试计数

    我有一个 AWS Lambda python3 7运行时 运行某个任务 及其MaximumRetryAttempts被设定为1 这意味着它可能会失败一次 然后再尝试一次 由于某种原因 我不会进入 我想知道 在运行时 这是第一次尝试还是第二次
  • Scala:没有明确已知类型参数的类型转换

    考虑以下示例 case class C T x T def f t T println t type ValueType T val list List 1 gt C 2 hello gt C goodbye for a b lt list