2013-03-05 3 views
1

Следующий Scala код работает правильно:Столкновение implicits в Scala

val str1 = "hallo" 
val str2 = "huhu" 
val zipped: IndexedSeq[(Char, Char)] = str1.zip(str2) 

Однако, если я импортировать неявного метода

implicit def stringToNode(str: String): xml.Node = new xml.Text(str) 

затем Scala (2,10) компилятор выдает ошибку: value zip is not a member of String

Кажется, что наличие stringToNode каким-то образом блокирует неявное преобразование str1 и str2 - WrappedString. Зачем? И есть способ изменить stringToNode так, что zip работает, но stringToNode по-прежнему используется, когда я вызываю функцию, которая требует аргумента Node с String?

ответ

6

У вас есть двусмысленные импликации. Оба StringOps и xml.Node имеют zip-метод, поэтому неявное преобразование неоднозначно и не может быть разрешено. Я не знаю, почему это не дает лучшего сообщения об ошибке.

Вот некоторые ссылки, чтобы поддержать это: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.StringOps и http://www.scala-lang.org/api/current/index.html#scala.xml.Node

редактировать: он был StringOps, не WrappedString, изменил ссылки :) Взгляните на Predef: http://www.scala-lang.org/api/current/index.html#scala.Predef $ , чтобы увидеть предопределенные импликации в Scala.

В этом случае я бы избегал использования имплицитов. Вы хотите два разных неявных преобразования, которые предоставляют метод с тем же именем (zip). Я не думаю, что это возможно. Кроме того, если вы импортируете xml.Text, вы можете конвертировать только с Text(str), который должен быть достаточно кратким для любого. Если вы должны иметь это неявное преобразование в xml.Node, я бы упаковал неявный def в объект, а затем импортировал его только в тех местах, где он вам нужен, чтобы сделать ваш код доступным для чтения и, возможно, избежать конфликтов, в которых вам также необходимо zip строк. Но в принципе, я бы очень избегал использовать implicits, чтобы сделать удобные преобразования.

+0

Спасибо! Есть ли способ избежать этой двусмысленности? Могу ли я представить какие-то предпочтения? –

+0

Я думаю, что вы столкнетесь с проблемой, что Predef всегда в области видимости, поэтому, если вы вызываете метод, который существует как для StringOps, так и для xml.Node, компилятор не сможет выбрать соответствующий имплицитный. Вы можете попробовать иметь stringToNode в области видимости и сделать это: val x: xml.Node = "whatever-xml-thing", и посмотреть, будет ли это срабатывать. Но тогда вы не сможете использовать zip в текущей области! – Felix

3

Как @Felix написал, как правило, плохая идея определить неявные преобразования между похожими типами данных, как тот, который вы использовали. Выполнение этой системы ослабляет тип, приводит к неоднозначностям, как вы встречались, и может создавать крайне неясный («волшебный») код, который очень трудно анализировать и отлаживать.

Неявные преобразования в Scala в основном используются для определения коротких коротких оболочек, чтобы обогатить API завернутого типа. Неявное преобразование, которое преобразует String в WrappedString, относится к этой категории.

В разделе «Effective Scala» Twitter есть раздел об этой проблеме.

Смежные вопросы