Evitar ambigüidade def implícita no Scala

votos
15

Eu estou tentando criar uma conversão implícita de qualquer tipo (por exemplo, int) para uma cadeia ...

Uma conversão implícita para String significa métodos RichString (como o reverso) não estão disponíveis.

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

Uma conversão implícita para RichString significa métodos de corda (como ToCharArray) não estão disponíveis

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

Utilizando ambas as conversões implícitas significa métodos duplicados (como comprimento) são ambíguos.

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: ?}

Assim, é possível converter implicitamente para String e ainda suportar todos os métodos de String e RichString?

Publicado 27/08/2009 em 07:15
fonte usuário
Em outras línguas...                            


6 respostas

votos
5

Como de Scala 2,8, este foi melhorado. De acordo com este papelevitar ambiguidades ):

Anteriormente, a fi mais específica c método sobrecarregado ou conversão implícita seria escolhido com base exclusivamente no tipos de argumentos do método. Havia uma cláusula adicional que disse que o método fi c mais específico não poderia ser definida em uma superclasse adequada de qualquer das outras alternativas. Este regime foi substituído em Scala 2,8 pela seguinte, mais liberal um: Ao comparar duas alternativas aplicáveis diferentes de um método sobrecarregado ou de um implícito, cada método obtém um ponto para ter mais argumentos específicos, e um outro ponto de ser definida em uma subclasse adequada. Uma alternativa “ganha” em detrimento de outro se ele recebe um maior número de pontos nas duas comparações. Isto significa, em particular, que se alternativas têm tipos de argumentos idênticos, o que é definido em uma subclasse ganha.

Veja que outro papel (§6.5) para um exemplo.

Respondeu 16/01/2011 em 13:53
fonte usuário

votos
5

Eu não tenho uma solução, mas vai comentar que a razão RichStringmétodos não estão disponíveis após a sua intToStringimplícita é que Scala não cadeia chamadas implícitas (ver 21.2 "Regras para implícitos" em Programação em Scala ).

Se você introduzir um intermediário String, Scala vai fazer a converstion implict a um RichString(ou implícita é definida em Predef.scala).

Por exemplo,

$ 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
Respondeu 27/08/2009 em 10:07
fonte usuário

votos
2

A solução aceita (postado por Mitch Blevins) nunca vai funcionar: downcasting Intpara Stringusar asInstanceOfsempre falhará.

Uma solução para o seu problema é adicionar uma conversão de qualquer tipo String-conversível para RichString(ou melhor, de StringOpscomo é agora chamado):

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

Em seguida, defina a sua conversão (s) para string como antes:

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
Respondeu 06/05/2015 em 08:18
fonte usuário

votos
2

Ou fazer uma classe de proxy enorme, ou chupa-lo e exigir que o cliente disambiguate-lo:

100.asInstanceOf [String] .length

Respondeu 27/08/2009 em 09:57
fonte usuário

votos
2

A única opção que vejo é para criar uma nova classe MyString Wrapper Cordas e deixe que a chamada qualquer método que você quer ser chamado no caso ambíguo. Em seguida, você pode definir conversões implícitas para MyString e duas conversões implícitas de MyString para String e RichString, apenas no caso de necessidade de passá-lo para uma função de biblioteca.

Respondeu 27/08/2009 em 07:37
fonte usuário

votos
1

Estou confuso: você não pode usar .toStringem qualquer tipo de qualquer maneira evitando assim a necessidade de conversões implícitas?

Respondeu 27/08/2009 em 08:56
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more