Как избежать неявной неопределенности def в Scala - PullRequest
15 голосов
/ 27 августа 2009

Я пытаюсь создать неявное преобразование из любого типа (скажем, Int) в строку ...

Неявное преобразование в String означает, что методы RichString (например, reverse) недоступны.

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 ]

5 голосов
/ 16 января 2011

В Scala 2.8 это было улучшено. Согласно этой статье Избежание неясностей ):

Ранее самый специфический перегруженный метод или неявное преобразование будет выбран только на основе типов аргументов метода. Это был дополнительный пункт, в котором говорится, что самый конкретный метод не может быть определяется в надлежащем суперклассе любой из других альтернатив. это схема была заменена в Scala 2.8 следующей, более либеральной: При сравнении двух разных применимых альтернатив перегруженных метод или неявный, каждый метод получает одну точку за более конкретные аргументы и еще один момент для определения в собственном подкласс. Альтернатива «выигрывает» над другой, если получает большее число очков в этих двух сравнениях. Это означает, в частности, что если альтернативы имеют идентичные типы аргументов, тот, который определен в выигрывает подкласс.

См. этот другой документ (§6.5) для примера.

5 голосов
/ 27 августа 2009

У меня нет решения, но я прокомментирую, что причина 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
2 голосов
/ 06 мая 2015

Принятое решение (опубликованное Митчем Блевинсом) никогда не будет работать: понижение Int до String с использованием asInstanceOf всегда будет неудачным.

Одним из решений вашей проблемы является добавление преобразования из любого типа, преобразуемого в строку, в 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
2 голосов
/ 27 августа 2009

Либо создайте огромный прокси-класс, либо воспользуйтесь им и потребуйте от клиента устранения неоднозначности:

2 голосов
/ 27 августа 2009

Единственный вариант, который я вижу, - это создать новый класс String Wrapper MyString и позволить этому вызывать любой метод, который вы хотите вызвать в неоднозначном случае. Затем вы можете определить неявные преобразования в MyString и два неявных преобразования из MyString в String и RichString, на тот случай, если вам нужно передать их в библиотечную функцию.

1 голос
/ 27 августа 2009

Я в замешательстве: разве вы не можете использовать .toString для любого типа, тем самым избегая необходимости неявных преобразований?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...