让我说我有这个特质
trait Ctx[C, V[_]]
我无法构造任何采用Ctx的方法签名,其中第二个类型参数未指定(通配符)。例如。这样:
def test(c: Ctx[_, _]) = ()
无法编译("error: _$2 takes no type parameters, expected: one"
)。我也不能
def test(c: Ctx[_, _[_]]) = ()
("error: _$2 does not take type parameters"
)。我错过了什么?
答案 0 :(得分:5)
我能够定义这个:
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
是不同类型构造函数的对象(选项和列表 in我的例子)。我提供的第一个解决方案不允许你这样做。
编辑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) }
答案 1 :(得分:3)
您需要为Ctx
的第二个参数传递一个类型构造函数。如果您只是传递_
,Scala无法推断出正确的类型。也不可能动态定义带有通配符的类型构造函数(即_[_]]
。请注意,在第一个示例中,错误消息中的_$2
引用作为第二个参数传递给{{1}的类型在第二个示例中,Ctx
引用_$2
中的第一个通配符类型。请参阅错误消息中的位置指示符:
_[_]
以下作品此处<console>:6: error: _$2 does not take type parameters
def test( c: Ctx[ _, _[ _ ]]) {}
^
是V
期望的正确类型的类型构造函数。
Ctx
答案 2 :(得分:-1)
所有解释都是here。关注底部的“常见陷阱”部分。