Импорт общих последствий из экземпляров классов
Я пытаюсь сделать универсальный неявный поставщик, который может создать неявное значение для данного типа, что-то в строках:
trait Evidence[T]
class ImplicitProvider[T] {
class Implementation extends Evidence[T]
implicit val evidence: Evidence[T] = new Implementation
}
Чтобы использовать это неявное, я создаю val provider = new ImplicitProvider[T]
экземпляр где надо и импорт из него import provider._
, Это прекрасно работает, пока есть только один экземпляр. Однако иногда последствия для нескольких типов необходимы в одном месте.
case class A()
case class B()
class Test extends App {
val aProvider = new ImplicitProvider[A]
val bProvider = new ImplicitProvider[B]
import aProvider._
import bProvider._
val a = implicitly[Evidence[A]]
val b = implicitly[Evidence[B]]
}
И это не компилируется с could not find implicit value for parameter
а также not enough arguments for method implicitly
ошибки.
Если я использую неявные значения от поставщиков напрямую, все снова начинает работать.
implicit val aEvidence = aProvider.evidence
implicit val bEvidence = bProvider.evidence
Однако я стараюсь не импортировать отдельные значения, поскольку внутри каждого провайдера есть несколько последствий, и цель состоит в том, чтобы абстрагировать их, если это возможно.
Можно ли это как-то достичь или я хочу слишком многого от компилятора?
1 ответ
Проблема заключается в том, что когда вы импортируете из обоих объектов, вы вводите две сущности, имена которых совпадают: evidence
в aProvider
а также evidence
в bProvider
, Компилятор не может устранить их неоднозначность, как из-за того, как он реализован, так и из-за того, что имплициты, которые уже могут быть загадочными, могли бы делать вещи, которые не могут быть выполнены явно (устранение неоднозначности между конфликтующими именами).
То, что я не понимаю, в чем смысл ImplicitProvider
является. Вы можете вытащить Implementation
класс на верхний уровень и иметь object
где-то держит implicit val
s.
class Implementation[T] extends Evidence[T]
object Evidence {
implicit val aEvidence: Evidence[A] = new Implementation[A]
implicit val bEvidence: Evidence[B] = new Implementation[B]
}
// Usage:
import Evidence._
implicitly[Evidence[A]]
implicitly[Evidence[B]]
Теперь нет названия столкновения.
Если вам нужно иметь фактический ImplicitProvider
вместо этого вы можете сделать это:
class ImplicitProvider[T] { ... }
object ImplicitProviders {
implicit val aProvider = new ImplicitProvider[A]
implicit val bProvider = new ImplicitProvider[B]
implicit def ImplicitProvider2Evidence[T: ImplicitProvider]: Evidence[T]
= implicitly[ImplicitProvider[T]].evidence
}
// Usage
import ImplicitProviders._
// ...