避免Scala中的隐式def歧义

时间:2009-08-27 06:15:03

标签: string scala implicit ambiguous

我正在尝试创建从任何类型(例如,Int)到String ...

的隐式转换

对String的隐式转换意味着RichString方法(如反向)不可用。

implicit def intToString(i: Int) = String.valueOf(i)
100.toCharArray  // => Array[Char] = Array(1, 0, 0)
100.reverse // => error: value reverse is not a member of Int
100.length // => 3

隐式转换为RichString意味着String方法(如toCharArray)不可用

implicit def intToRichString(i: Int) = new RichString(String.valueOf(i))
100.reverse // => "001"
100.toCharArray  // => error: value toCharArray is not a member of Int
100.length // => 3

使用两个隐式转换意味着重复的方法(如长度)不明确。

implicit def intToString(i: Int) = String.valueOf(i)
implicit def intToRichString(i: Int) = new RichString(String.valueOf(i))
100.toCharArray  // => Array[Char] = Array(1, 0, 0)
100.reverse // => "001"
100.length // => both method intToString in object $iw of type 
   // (Int)java.lang.String and method intToRichString in object
   // $iw of type (Int)scala.runtime.RichString are possible 
   // conversion functions from Int to ?{val length: ?}

那么,是否可以隐式转换为String并仍然支持所有String和RichString方法?

6 个答案:

答案 0 :(得分:5)

我没有解决方案,但会在你的RichString隐含之后注释intToString方法不可用的原因是Scala不链接隐式调用(参见21.2“隐含规则”)在 Scala中编程)。

如果您引入中间版String,Scala会将隐含权转换为RichString(隐式在Predef.scala中定义)。

如,

$ scala
Welcome to Scala version 2.7.5.final [...].
Type in expressions to have them evaluated.
Type :help for more information.

scala> implicit def intToString(i: Int) = String.valueOf(i)
intToString: (Int)java.lang.String

scala> val i = 100
i: Int = 100

scala> val s: String = i
s: String = 100

scala> s.reverse
res1: scala.runtime.RichString = 001

答案 1 :(得分:5)

从Scala 2.8开始,这已经得到了改进。根据{{​​3}}(§避免歧义):

  

以前,最具体的重载方法或隐式转换   将仅基于方法的参数类型来选择。有一个   附加条款,说最具体的方法不可能   在任何其他替代方案的适当超类中定义。这个   Scala 2.8中的方案已由以下更自由的方案取代:   比较两种不同适用的超载替代方案   方法或隐含的方法,每个方法获得一个点以获得更多   特定的论点,以及另一个适当的定义点   子类。如果获得更多的数字,另一种选择“赢”另一个   这两个比较中的要点。 这尤其意味着如果   替代品具有相同的参数类型,即在a中定义的参数类型   子类获胜。

有关示例,请参阅this paper(§6.5)。

答案 2 :(得分:2)

我看到的唯一选择是创建一个新的String Wrapper类MyString,让它调用你想要在不明确的情况下调用的任何方法。然后,您可以定义MyString的隐式转换以及从MyString到String和RichString的两个隐式转换,以防您需要将其传递给库函数。

答案 3 :(得分:2)

要么制作一个巨大的代理类,要么吸收它并要求客户端消除它的歧义:

100.asInstanceOf [字符串]。长度

答案 4 :(得分:2)

接受的解决方案(由Mitch Blevins发布)永远不会奏效:使用IntString转发asInstanceOf将始终失败。

您的问题的一个解决方案是将任何String-convertible类型的转换添加到RichString(或者更确切地说,添加到StringOps,因为它现在已命名):

implicit def stringLikeToRichString[T](x: T)(implicit conv: T => String) = new collection.immutable.StringOps(conv(x))

然后像以前一样将转换定义为字符串:

scala> implicit def intToString(i: Int) = String.valueOf(i)
warning: there was one feature warning; re-run with -feature for details
intToString: (i: Int)String

scala> 100.toCharArray
res0: Array[Char] = Array(1, 0, 0)

scala> 100.reverse
res1: String = 001

scala> 100.length
res2: Int = 3

答案 5 :(得分:1)

我很困惑:你不能在任何类型上使用.toString,因此无需隐式转换吗?

相关问题