Проблема в том, что вы должны использовать импликации с аннотациями всегда.
Теперь, когда вы используете их, когда они не аннотированы, вы попадаете в некую неопределенную / недопустимую зону поведения. Вот почему с аннотированным случается что-то вроде этого:
- Я хочу использовать
Decoder[List[URL]]
- нет (аннотированный)
Decoder[List[URL]]
неявный в области действия
- давайте выведем его как обычно (не нужно
generic.auto._
, потому что определение для этого есть в сопутствующем объекте)
- после получения вы вызываете его .prepare (_. DownField ("выполнено"))
- конечный результат имеет тип
Decoder[List[URL]]
, так что выводится тип decodeCompleted
Теперь, что произойдет, если вы аннотируете?
- Я хочу использовать
Decoder[List[URL]]
- существует
decodeCompleted
, объявленный как нечто, удовлетворяющее этому определению
- пусть использовать
decodeCompleted
значение
- но
decodeCompleted
не инициализирован! фактически мы инициализируем его прямо сейчас!
- в результате вы получите
decodeCompleted = null
Это практически равно:
val decodeCompleted = decodeCompleted
за исключением того, что слой косвенности становится способом обнаружения абсурда этого компилятором. (Если вы замените val
на def
, вы получите бесконечную рекурсию и переполнение стека):
@ implicit val s: String = implicitly[String]
s: String = null
@ implicit def s: String = implicitly[String]
defined function s
@ s
java.lang.StackOverflowError
ammonite.$sess.cmd1$.s(cmd1.sc:1)
ammonite.$sess.cmd1$.s(cmd1.sc:1)
ammonite.$sess.cmd1$.s(cmd1.sc:1)
ammonite.$sess.cmd1$.s(cmd1.sc:1)
Да, это запутано компилятором. Вы не сделали ничего плохого, и в идеальном мире это сработало бы.
Сообщество Scala смягчает это, выделяя:
- автоопределение - когда вам нужно где-то неявное и оно автоматически выводится без определения для него переменной
- полуавтоматическое деривация - когда вы производите в значение и делаете это значение неявным
В последнем случае у вас обычно есть некоторые утилиты, такие как:
import io.circe.generic.semiauto._
implicit val decodeCompleted: Decoder[List[URL]] = deriveDecoder[List[URL]]
Это работает, потому что принимает неявное DerivedDecoder[A]
, а затем извлекает из него Decoder[A]
, поэтому вы никогда не получите сценарий implicit val a: A = implicitly[A]
.