Избегание неявной двусмысленности определения в Scala

StackOverflow https://stackoverflow.com/questions/1339148

Вопрос

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

Неявное преобразование в строку означает, что методы 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 означает, что строковые методы (такие как 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

Использование обоих неявных преобразований означает, что дублированные методы (например, length) неоднозначны.

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[строка].длина

Другие советы

У меня нет решения, но я прокомментирую причину 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

Начиная с версии Scala 2.8, это было улучшено.Согласно этот документИзбегание двусмысленностей) :

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

Видишь та другая бумага (§6.5) для примера.

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

Принятое решение (опубликованное Митчем Блевинсом) никогда не будет работать:принижение Int к 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 в любом случае для любого типа, что позволяет избежать необходимости неявных преобразований?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top