Ответ 1
Либо сделайте огромный прокси-класс, либо сосать его, и попросите его устранить его неоднозначно:
100.asInstanceOf [String].length
Я пытаюсь создать неявное преобразование из любого типа (скажем, Int) в String...
Неявное преобразование в 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?
Либо сделайте огромный прокси-класс, либо сосать его, и попросите его устранить его неоднозначно:
100.asInstanceOf [String].length
У меня нет решения, но прокомментирую, что методы причины RichString
недоступны после того, как ваш intToString
неявный означает, что Scala не связывает неявные вызовы (см. 21.2 "Правила для implicits" в Программе в 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
Что касается Scala 2.8, это было улучшено. По этот документ (§ Избегание неоднозначностей):
Ранее наиболее специфичный перегруженный метод или неявное преобразование будет выбираться исключительно на основе типов аргументов методов. Это был дополнительное предложение, в котором говорилось, что наиболее специфический метод не может быть определяемый в надлежащем суперклассе любой из других альтернатив. Эта схема была заменена в Scala 2.8 следующим, более либеральным: При сравнении двух разных применимых альтернатив перегруженного метод или неявный, каждый метод получает один балл за конкретные аргументы и еще один момент для определения в надлежащем подкласс. Альтернатива "выигрывает" над другой, если она получает большее число точек в этих двух сравнениях. Это означает, в частности, что если альтернативы имеют одинаковые типы аргументов, тот, который определен в побеждает подкласс.
См. эту другую статью (§6.5) для примера.
Единственное, что я вижу, это создать новый класс String Wrapper MyString и позволить ему вызывать любой метод, который вы хотите вызвать в неоднозначном случае. Затем вы можете определить неявные преобразования в MyString и два неявных преобразования из MyString в String и RichString, на всякий случай, если вам нужно передать его в библиотечную функцию.
Принятое решение (опубликовано Митчем Блевинсом) никогда не будет работать: downcasting Int
to String
с использованием asInstanceOf
всегда будет терпеть неудачу.
Одним из решений вашей проблемы является добавление преобразования из любого типа, преобразованного в String, в 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
Я смущен: не можете ли вы использовать .toString
для любого типа, тем самым избегая необходимости в неявных преобразованиях?