Scala 隐式转换陷阱

2023-12-29

EDIT
好的,@Drexin 提出了一个很好的观点:使用隐式转换器时类型安全性的损失/令人惊讶的结果。

一个不太常见的转换怎么样,不会与 PreDef 隐式发生冲突?例如,我正在 Scala 中使用 JodaTime(很棒的项目!)。在定义隐式的同一控制器包对象中,我有一个类型别名:

type JodaTime = org.joda.time.DateTime

以及将 JodaTime 转换为 Long 的隐式(对于构建在 ScalaQuery 之上的 DAL,其中日期存储为 Long)

implicit def joda2Long(d: JodaTime) = d.getMillis

这里,PreDef 和我的控制器包隐式之间不能存在歧义,并且控制器隐式不会过滤到 DAL,因为它位于不同的包范围中。所以当我这样做时

dao.getHeadlines(articleType, Some(jodaDate))

在我看来,到 Long 的隐式转换是安全地完成的,并且考虑到基于日期的查询被大量使用,我保存了一些样板文件。

类似地,对于 str2Int 转换,控制器层接收 servlet URI 参数作为 String -> String。在很多情况下,URI 会包含数字字符串,因此当我过滤路由以确定 String 是否为 Int 时,我不想每次都 stringVal.toInt ;相反,如果正则表达式通过,则让隐式将字符串值转换为 Int 。总的来说,它看起来像:

implicit def str2Int(s: String) = s.toInt
get( """/([0-9]+)""".r ) {
  show(captures(0)) // captures(0) is String
}
def show(id: Int) = {...}

在上述上下文中,这些隐式转换的有效用例是,还是总是显式的?如果是后者,那么what are有效的隐式转换用例?

ORIGINAL
In a 封装对象我定义了一些隐式转换,其中之一是简单的 String 到 Int:

implicit def str2Int(s: String) = s.toInt

一般来说,这种方法工作得很好,采用 Int 参数但接收 String 的方法会转换为 Int,就像返回类型设置为 Int 但实际返回值是 String 的方法一样。

太好了,现在在某些情况下,编译器会因可怕的模糊隐式错误:

类型为 (x: String) 的对象 Predef 中的两个方法 AugmentString scala.collection.immutable.StringOps 和方法 str2Int(s: String) Int 是否有可能从 java.lang.String 到 ?{val 的转换函数 toInt: ?}

我知道发生这种情况的情况是在尝试进行手动内联字符串到整数转换时。例如,val i = "10".toInt

我的解决方法/黑客方法是创建一个 asInt 帮助程序以及包对象中的隐式内容:def asInt(i: Int) = i并用作,asInt("10")

那么,隐式最佳实践是隐式的(即通过烧伤来学习),还是有一些指导方针可以遵循,以免陷入自己制造的陷阱?换句话说,是否应该避免简单、常见的隐式转换,而只在要转换的类型唯一的情况下使用? (即永远不会陷入歧义陷阱)

感谢您的反馈,隐式非常棒......当它们按预期工作时;-)


我认为您在这里混合了两种不同的用例。

在第一种情况下,您使用隐式转换来隐藏不同类之间在功能相同的情况下的任意区别(或者对您来说是任意区别)。这JodaTime to Long隐式转换属于该类别;这可能是安全的,而且很可能是个好主意。我可能会使用丰富我的图书馆模式,然后写

class JodaGivesMS(jt: JodaTime) { def ms = jt.getMillis }
implicit def joda_can_give_ms(jt: JodaTime) = new JodaGivesMS(jt)

and use .ms每次通话时,都要明确。原因是单位在这里很重要(毫秒不是微秒不是秒不是毫米,但都可以表示为整数),我宁愿离开some在大多数情况下,记录接口处的单位。getMillis每次打字都有点费劲,但是ms还不错。尽管如此,这种转换还是合理的(如果对未来几年可能修改代码的人(包括您)有充分的记录)。

然而,在第二种情况下,您在一种非常常见的类型和另一种非常常见的类型之间执行不可靠的转换。确实,您仅在有限的上下文中执行此操作,但该转换仍然容易逃脱并导致问题(异常或类型不是您的意思)。相反,您应该编写正确处理转换所需的方便例程,并在任何地方使用它们。例如,假设您有一个字段,您希望该字段为“是”、“否”或整数。你可能有类似的东西

val Rint = """(\d+)""".r
s match {
  case "yes" => println("Joy!")
  case "no" => println("Woe!")
  case Rint(i) => println("The magic number is "+i.toInt)
  case _ => println("I cannot begin to describe how calamitous this is")
}

但是这段代码is wrong, 因为"12414321431243".toInt当您真正想说的是情况是灾难性的时,会抛出异常。相反,您应该编写正确匹配的代码:

case object Rint {
  val Reg = """([-]\d+)""".r
  def unapply(s: String): Option[Int] = s match {
    case Reg(si) =>
      try { Some(si.toInt) }
      catch { case nfe: NumberFormatException => None }
    case _ => None
  }
}

并用这个代替。现在,与其执行危险的操作和隐含的转换自String to Int,当您执行匹配时,所有正则表达式匹配(以避免在错误解析时抛出和捕获大量异常)和异常处理(即使正则表达式通过)都会得到正确处理。

如果您有一个同时具有字符串和 int 表示形式的东西,请创建一个新类,然后对每个类进行隐式转换(如果您不希望使用该对象(您知道可以安全地使用其中之一))继续重复某个方法调用并没有真正提供任何启发。

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

Scala 隐式转换陷阱 的相关文章

随机推荐

  • 是否有编译器开关可以关闭 C# 中对泛型的支持?

    我正在与一位合作伙伴合作 尝试将复杂的驱动程序从 NET 平台迁移到 NET MicroFramework 问题是 NET MF 不支持泛型 当我们尝试构建应用程序时 最后一个 链接 操作会退出并显示错误代码 CLR E PARSER UN
  • Eclipse:哪些 HTML 和 Javascript 插件?

    您使用哪些插件在 Eclipse 3 5 中编辑 带语法突出显示 HTML 和 Javascript Spket http spket com 是一个很棒的 JavaScript 插件 对于 HTML 我通常只使用附带的默认 XML HTM
  • jQuery 同位素插件水平滚动

    fiddle http jsfiddle net xKjUv 19 只是想让它水平滚动文档示例 http isotope metafizzy co docs layout modes html 我不知道为什么它不起作用 container
  • Apache Spark SQL 需要很长时间才能计算 Cassandra 中的十亿行吗?

    我有以下代码 我按如下方式调用 Spark Shell spark shell conf spark cassandra connection host 170 99 99 134 executor memory 15G executor
  • 无法使用 SSMS 通过 Windows 身份验证连接到本地 SQL Server

    我正在尝试使用 SSMS 使用 Windows 身份验证登录到安装在 Windows 7 上的本地 SQL Server 2005 我尝试使用各种服务器名称 例如 localhost SQL ANANTH PC etc 当我尝试时出现此错误
  • Wordpress ACF - 日期格式

    我使用日期字段将日期呈现为 11 15 2014 但我还想在页面的其他位置显示日期 例如 2014 年 11 月 15 日 是否可以以两种不同的格式呈现日期 您可以使用get field然后您可以将日期格式更改为您想要的任何格式 date
  • ES6 Promise 中的数据只有在我点击它之后才会呈现在页面上?

    我在我的应用程序中使用 Ionic 并连接到 Firebase 来提取数据 我在工厂中创建了一个承诺 将数据拉下来 并认为一旦完成 它应该在屏幕上呈现数据 但在触摸屏幕之前我什么也得不到 我没有收到任何错误 数据确实出现了 Factory
  • jpa 实体 bean 的默认范围是什么?它有什么帮助?

    我的项目中的所有实体 bean 看起来都是这样的 我想知道对实体使用 scope prototype 的意义是什么 Component Scope prototype Entity Table name SOME BEAN SOME CON
  • 如何在iPhone锁屏状态下开始播放音乐

    我在用UILocalNotification如果应用程序未运行 则提醒用户MPMusicPlayerController播放 iPod 音乐和MPMoviePlayerController播放广播流 url 根据苹果文档 如果 iPhone
  • 以编程方式使用尺寸类别

    我 希望 观看了所有相关的 WWDC2014 会议视频并阅读了文档 所以这个问题主要是为了证实我的怀疑 但请赐教 我想做的是使用自动布局为视图添加动画效果 这本身并不是问题 但这些动画的端点随着不同的方向而变化 我想我也许可以使用尺寸类来自
  • 无法配置 Firebase InstanceID

    您好 我正在尝试在我的应用程序中包含 firebase 并遵循文档 当我尝试进行 google 登录时 出现无法配置 Firebase InstanceID 错误 请建议如何克服此错误 有两件事需要检查 希望其中一项能为您解决 确保您的捆绑
  • 无法从 Xcode 运行 Instruments

    我最近升级到 Snow Leopard 从那以后我很难运行 Instrument 来从 Xcode 检测我的应用程序 录制 按钮将变灰 并且什么也不会发生 Xcode 的控制台中也没有消息告诉我出了什么问题 我曾经能够将其附加到进程或从仪器
  • 如何使用 jQuery 在 IE 中附加样式表?

    大家好 我只是想创建一个插件 我需要它对用户友好 所以我想append the 标签上的head加载我的插件时用户页面的一部分 它适用于所有其他浏览器 不确定 IE9 IE7 和 IE6 但不适用于 IE8 我不知道我的插件出了什么问题 所
  • 在 CakePHP 中重写 php 应用程序

    因此 我很想使用 php 框架重写我的应用程序 因为我认为这会让人们更容易参与 并改进应用程序的设计 CakePHP 看起来是最好的 PHP Web 框架 有人有这方面的经验吗 从手动编写 PHP 到使用框架 我应该考虑哪些注意事项 不取决
  • 写入 Mac OS X 10.7 中的“~/Library/Application Support”文件夹

    我可以使用 NSFileManager 在 Mac OS X 10 5 和 10 6 中的 Library Application Support 中创建 XYZ 文件夹 然而 在 10 7 中 它显示 您无权将 XYZ 保存在文件夹 应用
  • Enterprise Library 5.0 - 将自定义标记添加到 TextFormatter

    我创建了一个自定义异常 其中包含与我们的应用程序相关的数据 我想确保在引发异常时记录这些数据并将其记录到事件日志中 我尝试创建一个正在调用的自定义 TextFormatter 但不确定如何访问当前异常 以便我可以将自定义信息添加到日志条目中
  • Google Vision ocr:垂直和水平线文本识别

    我们正在使用 google Vision ocr 来收集收据中的文本 在某些情况下 收据上有一些垂直书写的文本 例如增值税信息等 问题是 谷歌视觉仅有效地读取主方向 例如水平方向 的文本 并丢弃在同一收据中以垂直方向而不是水平方向写入的所有
  • 向下滚动并双击最后一个展开/折叠箭头时,TreeTableView 项目消失

    在与一个TreeTableView我意识到 当您向下滚动表格并双击最后一个展开 折叠箭头时 所有项目都会消失 但是 当您再次滚动时 所有项目都会重新出现 当然 当你有足够的物品时就会发生这种情况 因此垂直ScrollBar活跃 以前有人遇到
  • 为什么结构类型的编译时生成技术会阻止单独编译?

    我正在读 好吧 略读 杜博切特和奥德斯基的在 JVM 上编译结构类型 http infoscience epfl ch record 138931 files 2009 structural pdf并对以下说法感到困惑 Generative
  • Scala 隐式转换陷阱

    EDIT好的 Drexin 提出了一个很好的观点 使用隐式转换器时类型安全性的损失 令人惊讶的结果 一个不太常见的转换怎么样 不会与 PreDef 隐式发生冲突 例如 我正在 Scala 中使用 JodaTime 很棒的项目 在定义隐式的同