Как это может быть?
Предполагаемый тип Any
здесь является результатом того, что компилятор пытается найти общего предка Double
и Option[Nothing]
.Первый общий предок для обоих этих типов - Any
, и поэтому компилятор выводит это.
Почему тип совпадает в первую очередь, когда None
имеет тип Option[Nothing]
Отличный вопрос.Давайте проверим подпись для getOrElse
:
final def getOrElse[B >: A](default: => B): B
Давайте увеличим ограничение B >: A
, что это значит?Это означает, что мы можем указать любой тип B
, который является супертипом из A
.Почему мы хотим, чтобы это был супер тип A
для начала?Почему бы не A
сам?Если параметр типа заставит нас использовать A
здесь, мы будем ограничены Double
, и ваш пример не будет компилироваться.Чтобы ответить на этот вопрос, нам нужно взглянуть на определение Option[A]
:
sealed abstract class Option[+A]
Мы видим, что A
имеет +
рядом с ним.Этот плюс указывает на наличие ковариации.Короче говоря, ковариация позволяет нам сохранять «отношение подтипа» между типами, которые сами определены внутри других «контейнерных» типов, сохраняя следующее отношение:
A <: B <=> Option[A] <: Option[B]
Что означает, что A
являетсяподтип B
, мы можем рассматривать Option[A]
как подтип Option[B]
.Почему это важно и как это связано с сигнатурой метода getOrElse
?Ну, ковариация накладывает ограничения на параметры типа!Параметры ковариантного типа нельзя использовать в качестве входных параметров или в позиции входного параметра (позиция является контравариантной, если она встречается при нечетном количестве конструкторов контравариантного типа, но объяснение этого слишком длинное, поэтому я сокращусь), они могут толькобыть помещены в качестве выходных параметров в базовый тип, содержащий параметр типа.Таким образом, следующее определение является недопустимым из-за законов дисперсии:
final def getOrElse(default: => A): A
Поскольку A
появляется здесь и в типе ввода, и в типе вывода.