Scala — неявное преобразование с неприменением

Я бы хотел, чтобы экстрактор неявно преобразовывал свои параметры, но, похоже, это не работает. Рассмотрим этот очень простой случай:

case class MyString(s: String) {}

implicit def string2mystring(x: String): MyString = new MyString(x)
implicit def mystring2string(x: MyString) = x.s

object Apply {
    def unapply(s: MyString): Option[String] = Some(s)
}

Но я не могу использовать его так, как ожидал:

val Apply(z) = "a"  // error: scrutinee is incompatible with pattern type

Кто-нибудь может объяснить, почему не удается преобразовать параметр из String в MyString? Я ожидаю, что он вызовет string2mystring("a") на лету. Ясно, что я мог бы обойти проблему, сказав val Apply(y) = MyString("a"), но не похоже, что я должен был это делать.

Примечание. Этот вопрос аналогичен one, но 1) на самом деле нет хорошего ответа, почему это происходит, 2) пример сложнее, чем нужно.


person dhg    schedule 18.07.2011    source источник


Ответы (1)


Неявные преобразования не применяются при сопоставлении с образцом. Это не ошибка или проблема с вашим кодом, это просто дизайнерское решение создателей Scala.

Чтобы исправить это, вы должны написать еще один экстрактор, который принимает String, что, в свою очередь, может вызвать ваше неявное преобразование.

В качестве альтернативы вы можете попробовать с привязкой к представлению, которая, похоже, тоже работает, а также будет работать, если вы позже определите другие неявные преобразования в MyString:

object Apply {
  def unapply[S <% MyString](s: S): Option[String] = Some(s.s)
}
person Jean-Philippe Pellet    schedule 18.07.2011
comment
Спасибо. Это немного разочаровывает. Знаете ли вы, какова мотивация этого решения? - person dhg; 18.07.2011
comment
Да, добавление def unapply(p: String): Option[String] = Some(p) к Apply помогает. Так что я пойду с этим. Спасибо. - person dhg; 18.07.2011
comment
@dhg Я отредактировал ответ - кажется, что привязка к представлению тоже работает. - person Jean-Philippe Pellet; 18.07.2011
comment
Потрясающий! Ограничение представления - отличное решение. Это не только не требует написания дополнительных методов для каждого возможного типа, но и решает другую проблему, которая у меня была: если unapply принимает кортеж, вы не можете использовать трюк с перегрузкой из-за стирания типа. Но это решает проблему чисто и приводит к ошибкам времени компиляции для неправильных типов аргументов: def unapply[S <% MyString](p: (S, Int)): Option[String] = Some(p._1.s + p._2). - person dhg; 18.07.2011