Как использовать подстановочный знак для более высокого типа в Scala?
допустим, у меня есть эта черта
trait Ctx[C, V[_]]
Я не могу создать сигнатуру метода, которая принимает Ctx, параметр второго типа которого не указан (подстановочный знак). Е. Г. это:
def test(c: Ctx[_, _]) = ()
не компилируется ("error: _ takes no type parameters, expected: one"
). Ни я могу сделать
def test(c: Ctx[_, _[_]]) = ()
("error: _ does not take type parameters"
). Что я упускаю?
3 ответов
Я могу определить этот:
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 избавляет вас от сложной (или невозможной) задачи вычисления синтаксиса параметра типа для конструктора подстановочного типа. Дополнительно, как показано в the ListBuffer пример вы можете обрабатывать объекты, где V
является конструктором другого типа (опции и список в моем примере). Первое решение, которое я предложил, не позволит вам этого сделать.
Edit 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) }
вам нужно передать конструктор типа для второго аргумента Ctx
. Scala не в состоянии сделать правильный вывод, если вы просто пройти _
. Также невозможно определить конструктор типа с подстановочными знаками (т. е. _[_]]
на лету. Обратите внимание, что в первом примере _
в сообщении об ошибке ссылается на тип, переданный в качестве второго аргумента Ctx
в целом. Во втором примере, однако _
относится к первому типу wildcard в _[_]
. Индикатор местоположения в сообщениях об ошибках:
<console>:6: error: _ does not take type parameters
def test( c: Ctx[ _, _[ _ ]]) {}
^
следующие работы, так как здесь V
является конструктором типа правильного типа, ожидаемого Ctx
.
def test[V[_]]( c: Ctx[ _, V]) {}
все объяснено здесь. Сосредоточьтесь на разделе" Общие подводные камни " внизу.