Простой пример для иллюстрации вопроса:Почему scala не выводит вывод типа для f-связанного полиморфизма?
trait WTF[W <: WTF[W]] {
def get : Int
}
trait Zero extends WTF[Zero] {
override def get : Int = 0
}
case object Zero extends Zero
final case class Box(inner : Int) extends WTF[Box] {
override def get : Int = inner
}
def printWTF[W <: WTF[W]](w : W) = println(w.get)
printWTF(Box(-1))
printWTF(Zero)
Box
это нормально, но Zero
производит ошибку:
WTF.scala:22: error: inferred type arguments [Zero.type] do not conform to method printWTF's type parameter bounds [W <: WTF[W]]
printWTF(Zero)
^
WTF.scala:22: error: type mismatch;
found : Zero.type
required: W
printWTF(Zero)
^
two errors found
Если я аннотирования тип вручную, он компилирует:
printWTF[Zero](Zero)
printWTF(Zero : Zero)
Первый линия работает, как ожидалось. Я часто сталкиваюсь с случаями, когда параметры типа не могут быть выведены из аргументов. например def test[A](x : Int) : Unit
. Тип A
нигде не встречается в сигнатуре аргумента, поэтому вы должны указать его вручную.
Но последнее очень мало для меня. Я просто добавил тип приведения, который всегда является истинным, и чудом компилятор узнает, как вывести параметры типа метода. Но Zero
всегда из Zero
типа, почему компилятор не мог вывести его без подсказок от меня?
> объект Case Нулевой имеет тип Zero.type и является подтипом WTF [Zero] Но общее правило заключается в том, что вы можете заменить любую запись класса любым подклассом. Пример второй строки делает то же самое. Он не меняет подписи типов. – ayvango
Я не думаю, что кто-то знает полные правила вывода типа в Scala. Все, что я знаю, это то, что он не повторяет для всех супер типов «Zero.type» в вашем примере и что вам нужно немного помочь с некоторыми дополнительными параметрами, как я. И если вы имели в виду, что вы можете заменить «Zero» в 'WTF [Zero]' на 'Zero.type', вы ошибаетесь, потому что' W' в 'WTF' является инвариантным. –
Я не имел в виду, что 'Zero' внутри' WTF [Zero] 'может быть заменен. Но где угодно, где ожидаемый аргумент «Zero» он может быть заменен на «Zero.type», потому что вызов функции разрешен, 'Function [Zero, T]' является подтипом функции [Zero.type, T] ' – ayvango