Учитывая следующий фрагмент кода:
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)», которые неоднозначны. Поэтому я попытался изменить сигнатуру, добавив неявный список параметров.
Прочитав статью о type erasure и DummyImplicit и ознакомьтесь со справочным разделом Scala «7.2 Неявные параметры», я подумал, что «(implicit dummy: DummyImplicit)» помогут.
На данный момент мое решение состоит в том, чтобы иметь минимальную оболочку:
final case class Txt(str: String) {
override def toString = str
}
Учитывая, что неявное значение типа «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)
}