簡體   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