【问题标题】:Collision of implicits in ScalaScala中的隐式冲突
【发布时间】:2013-03-06 03:42:05
【问题描述】:

以下 Scala 代码可以正常工作:

val str1 = "hallo"
val str2 = "huhu"
val zipped: IndexedSeq[(Char, Char)] = str1.zip(str2)

但是,如果我导入隐式方法

implicit def stringToNode(str: String): xml.Node = new xml.Text(str)

然后 Scala (2.10) 编译器显示错误:value zip is not a member of String

似乎stringToNode 的存在以某种方式阻止了str1 和str2 到WrappedString 的隐式转换。为什么?有没有办法修改stringToNode 使得zip 可以工作,但是当我调用需要Node 参数和String 的函数时仍然使用stringToNode?

【问题讨论】:

    标签: scala implicit-conversion implicit


    【解决方案1】:

    你在这里有模棱两可的暗示。 StringOps 和 xml.Node 都有 zip 方法,因此隐式转换不明确,无法解析。我不知道为什么它没有给出更好的错误信息。

    以下是一些备份链接: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.StringOps 和 http://www.scala-lang.org/api/current/index.html#scala.xml.Node

    编辑:是 StringOps,不是 WrappedString,更改了链接 :) 看看 Predef:http://www.scala-lang.org/api/current/index.html#scala.Predef$ 查看 Scala 中的预定义隐式。

    在这种情况下我会避免使用隐式。您需要 2 个不同的隐式转换,它们都提供同名的方法 (zip)。我不认为这是可能的。此外,如果您导入 xml.Text,您可以只使用 Text(str) 进行转换,这对于任何人来说都应该足够简洁。如果您必须将此隐式转换为 xml.Node,我会将隐式 def 打包到一个对象中,然后仅将其导入您需要它以使您的代码可读的地方,并可能避免在您还需要的地方发生冲突拉链字符串。但基本上,我会非常避免使用隐式来进行方便的转换。

    【讨论】:

    • 谢谢!有没有办法避免这种歧义?我可以介绍一些偏好吗?
    • 我想你会遇到 Predef 总是在作用域内的问题,所以如果你调用一个同时存在于 StringOps 和 xml.Node 上的方法,编译器将无法选择合适的隐含的。您可以尝试在范围内使用 stringToNode 并执行以下操作:val x:xml.Node = "whatever-xml-thing",然后查看它是否启动。但是您将无法在当前范围内使用 zip!
    【解决方案2】:

    就像@Felix 写的那样,定义相似数据类型之间的隐式转换通常是一个坏主意,就像您使用的那样。这样做会削弱类型系统,导致像您遇到的模棱两可,并可能产生非常不清楚(“神奇”)的代码,很难分析和调试。

    Scala 中的隐式转换主要用于定义轻量级、短寿命的包装器,以丰富包装类型的 API。将String 转换为WrappedString 的隐式转换属于该类别。

    Twitter 的 Effective Scala 有一个关于此问题的部分。

    【讨论】:

      猜你喜欢
      • 2012-02-21
      • 2016-07-25
      • 1970-01-01
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      相关资源
      最近更新 更多