Я могу определить это:
def test[V[X]](c:Ctx[_,V]) {}
И вроде бы нормально работает с выводом типа:
scala> trait Ctx[ C, V[ _ ]]
defined trait Ctx
scala> def test[V[X]](c:Ctx[_,V]) {}
test: [V[X]](c: Ctx[_, V])Unit
scala> class P extends Ctx[Int, List]
defined class P
scala> new P
res0: P = P@1f49969
scala> test(res0)
Редактировать : Я подозреваю, что не будет практичным заменить Ctx
на использование абстрактного типа, но это то, что я смог сделать:
trait Ctx[C] { type V[X] }
class CtxOption[C] extends Ctx[C] { type V[X] = Option[X] }
class CtxList[C] extends Ctx[C] { type V[X] = List[X] }
def test(ctx:Ctx[_]) { println(ctx) }
val ctxOptInt = new CtxOption[Int]
val ctxListStr = new CtxList[String]
test(ctxOptInt)
test(ctxListStr)
val list = collection.mutable.ListBuffer[Ctx[_]]()
list += ctxOptInt
list += ctxListStr
list
Использование абстрактного типа для V избавляет вас от сложной (или невозможной) задачи определения синтаксиса параметра типа для конструктора подстановочного типа. Кроме того, как показано в примере ListBuffer , вы можете обрабатывать объекты, в которых V
является конструктором другого типа ( Option и List в моем примере). Первое решение, которое я предоставил, не позволило бы вам сделать это.
Редактировать 2 : Как насчет?
trait AbstractCtx[C] { type W[X] }
trait Ctx[C,V[_]] extends AbstractCtx[C] { type W[X] = V[X] }
def test(ctx:AbstractCtx[_]) { println(ctx) }