Ответ 1
Вам нужно будет изменить подпись callFoo
на следующее:
def callFoo[A, B, FF[A, B] <: Foo[A, B]](f: FF[A, B]): FF[A, B]#F[A, B] =
Вы должны сообщить компилятору, что FF
на самом деле является параметризованным типом.
Когда я пытаюсь скомпилировать небольшой пример:
trait Foo[A,B] {
type F[_,_]
def foo(): F[A,B]
}
class Bar[A,B] extends Foo[A,B] {
type F[D,E] = Bar[D,E]
def foo() = this
}
object Helper {
def callFoo[A,B,FF <: Foo[A,B]]( f: FF ): FF#F[A,B] =
f.foo()
}
object Run extends App {
val x = new Bar[Int,Double]
val y = Helper.callFoo(x)
println( y.getClass )
}
Я получаю сообщение об ошибке:
[error] src/Issue.scala:20: inferred type arguments
[Nothing,Nothing,issue.Bar[Int,Double]] do not conform to method callFoo type
parameter bounds [A,B,FF <: issue.Foo[A,B]]
[error] val y = Helper.callFoo(x)
По-видимому, механизм вывода типа не может вывести A и B из бара [A, B]. Однако он работает, если я передаю все типы вручную:
val y = Helper.callFoo[Int,Double,Bar[Int,Double]](x)
Есть ли способ избежать передачи типов явно?
Вам нужно будет изменить подпись callFoo
на следующее:
def callFoo[A, B, FF[A, B] <: Foo[A, B]](f: FF[A, B]): FF[A, B]#F[A, B] =
Вы должны сообщить компилятору, что FF
на самом деле является параметризованным типом.
Будет ли работать использование членов типа вместо параметров?
trait Foo {
type A
type B
type F
def foo(): F
}
class Bar extends Foo {
type F = Bar
def foo() = this
}
object Helper {
def callFoo[FF <: Foo]( f: FF ): FF#F =
f.foo()
}
object Run extends App {
val x = new Bar{type A=Int; type B=Double}
val y = Helper.callFoo(x)
println( y.getClass )
}
При использовании членов типа полезно знать, что они могут отображаться как параметры типа с использованием уточнения, как в ответе Майлза Сабина: Почему эта циклическая ссылка с типом нелегальной?
См. также этот недавний вопрос, который похож на ваш: Scala не выводит правильные аргументы типа