Почему DummyImplicit не устраняет неоднозначность [String] (a: A) из (a: String) - PullRequest
1 голос
/ 23 августа 2011

С учетом следующего фрагмента кода:

final case class Attr[A](name: String)(implicit conv: String To A) {
  def apply(value: A)(implicit dummy: DummyImplicit) = Attribute(name, value)
  def apply(value: String) = Attribute[A](name, value)
}

Компилятор Scala жалуется на «неоднозначную ссылку на перегруженное определение», когда видит следующие значения:

1| val FooAttr = Attr[String]("foo")
2| val catch22 = FooAttr("bar")

Строка 1:Я намереваюсь передать фабрике «Attr», производящей «Attributes», тип значения «String», а также имя «foo» для всех атрибутов, которые он когда-либо создает.

Строка 2: Использование ранеенастроенная фабрика атрибутов Я фактически создаю атрибут с именем "foo" со значением "bar" типа "String".

Мой вывод: поскольку параметризованный тип "A" для этого объекта фабрики является "String",Компилятор Scala выводит те же сигнатуры параметров метода «apply» Being »(value: String)», которые неоднозначны.Поэтому я попытался изменить подпись, добавив список неявных параметров.

Прочитав статью о стирании типов и DummyImplicit и обратившись к справочному разделу Scala «7.2 Неявные параметры» Я подумал, что "(неявная пустышка: DummyImplicit)" добьется цели .

На данный момент мое решение состоит в том, чтобы иметь минимальную оболочку:неявное значение типа "Str To Txt", то есть подходящая функция преобразования, может быть найдено, вторая строка сверху компилируется, т.е.:

2| val catch22 = FooAttr("bar")

Кажется, я думал слишком сложным.Вместо того, чтобы перегружать метод apply списком параметров (value: String), я просто избавился от него.Версия, которая соответствует моим ожиданиям, теперь выглядит так:

final case class Attr[A](name: String)(implicit conv: String To A) {
  def apply(value: A) = Attribute(name, value)
}

1 Ответ

1 голос
/ 23 августа 2011

Как насчет этого?

case class Attribute[A](name: String, value: A)

case class AttrBuilder[A](name: String)(implicit conv: String => A) {
  def apply[B](value: B)(implicit conv: B => A) = Attribute(name, conv(value))
}

val bldr = new AttrBuilder[String]("MyAttrs")

bldr("hello") // Attribute(MyAttrs, hello)

implicit def int2string(x: Int) = x.toString
bldr(2)       // Attribute(MyAttrs, 2), using int2string implicit

bldr(false)   // fails; cannot find implicit Boolean => String

Конструктор атрибутов bldr примет любое значение типа B, которое можно преобразовать в A == String, включая сами строки (в этом случае используется неявное преобразование Predef.conforms).

...