В конечном итоге я хочу предоставить одну реализацию класса типа для определенного типа T
и другую реализацию для всех других типов, которые не являются T
. Я думал (возможно, неправильно), что самый простой способ сделать это — попробовать отрицание типа с помощью неоднозначных имплицитов, как описано в этот вопрос. Однако, если я случайно пропущу объявление класса неявного типа, мой код все равно скомпилируется (должен ли?), но будет содержать ошибки, поскольку используется только одна из реализаций.
Вот как определяется привязка контекста:
scala> trait NotAnInt[A]
defined trait NotAnInt
scala> implicit def everythingIsNotAnInt[A]: NotAnInt[A] = new NotAnInt[A] {}
everythingIsNotAnInt: [A]=> NotAnInt[A]
scala> implicit def intsAreInts1: NotAnInt[Int] = ???
intsAreInts1: NotAnInt[Int]
scala> implicit def intsAreInts2: NotAnInt[Int] = ???
intsAreInts2: NotAnInt[Int]
scala> implicit def nothingsAreInts1: NotAnInt[Nothing] = ???
nothingsAreInts1: NotAnInt[Nothing]
scala> implicit def nothingsAreInts2: NotAnInt[Nothing] = ???
nothingsAreInts2: NotAnInt[Nothing]
На данный момент NotAnInt[T] вызывается для всех T, кроме Int/Nothing:
scala> implicitly[NotAnInt[String]]
res3: NotAnInt[String] = $anon$1@1a24fe09
scala> implicitly[NotAnInt[Int]]
<console>:16: error: ambiguous implicit values:
both method intsAreInts1 of type => NotAnInt[Int]
and method intsAreInts2 of type => NotAnInt[Int]
match expected type NotAnInt[Int]
implicitly[NotAnInt[Int]]
^
scala> implicitly[NotAnInt[Nothing]]
<console>:18: error: ambiguous implicit values:
both method nothingsAreInts1 of type => NotAnInt[Nothing]
and method nothingsAreInts2 of type => NotAnInt[Nothing]
match expected type NotAnInt[Nothing]
implicitly[NotAnInt[Nothing]]
^
Теперь у меня определена привязка контекста NotAnInt
, и я могу создать свой класс типов с его реализациями:
scala> trait IntChecker[A] { def isInt(): Boolean }
defined trait IntChecker
scala> implicit val intIntChecker: IntChecker[Int] = new IntChecker[Int] { override def isInt = true }
intIntChecker: IntChecker[Int] = $anon$1@585dd35c
scala> implicit def otherIntChecker[A: NotAnInt]: IntChecker[A] = new IntChecker[A] { override def isInt = false }
otherIntChecker: [A](implicit evidence$1: NotAnInt[A])IntChecker[A]
Этот класс типа можно использовать, как и ожидалось:
scala> def printIntStatus[T: IntChecker](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatus: [T](t: T)(implicit evidence$1: IntChecker[T])Unit
scala> printIntStatus(3)
true
scala> printIntStatus("three")
false
Однако также компилируется следующее:
scala> def printIntStatusWithBug[T](t: T): Unit = { println(implicitly[IntChecker[T]].isInt()) }
printIntStatusWithBug: [T](t: T)Unit
scala> printIntStatusWithBug(3)
false
scala> printIntStatusWithBug("three")
false
Я бы не ожидал, что эта вторая функция скомпилируется, поскольку не должно быть неявного IntChecker[T]
. Я ожидаю, что everythingIsNotAnInt
является причиной этой проблемы, но я не могу придумать, как это обойти.
Меня интересует, почему этот подход терпит неудачу, а также альтернативные методы достижения того же самого. Спасибо.