繁体   English   中英

如何在Scala中使用通配符来获得更高级的类型?

[英]How to use a wildcard for a higher-kinded type in Scala?

比方说我有这个特点

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" )。 我错过了什么?

我能够定义这个:

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是不同类型构造函数的对象(在我的示例中为OptionList )。 我提供的第一个解决方案不允许你这样做。

编辑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无法推断出正确的类型。 也不可能动态定义带有通配符的类型构造函数(即_[_]] 。请注意,在第一个示例中,错误消息中的_$2指的是作为整体作为第二个参数传递给Ctx的类型。但是第二个例子_$2引用了_[_]的第一个通配符类型。请参阅错误消息中的位置指示符:

<console>:6: error: _$2 does not take type parameters
       def test( c: Ctx[ _, _[ _ ]]) {}
                            ^

以下工作,因为这里VCtx期望的正确类型的类型构造函数。

def test[V[_]]( c: Ctx[ _, V]) {}

这一切都在这里解释。 关注底部的“常见陷阱”部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM