2015-11-06 66 views
2

我試圖使用表達式來映射選項,但我只想匹配如果選項的內容是特定類型。我想會的工作是這樣的:是否可以在Scala中爲表達式匹配類型?

for { 
    vcs: Mercurial <- maybeVcs 
} yield vcs 

但是,這會產生以下編譯錯誤:

<console>:76: error: type mismatch; 
found : sbtrelease.Mercurial => sbtrelease.Mercurial 
required: sbtrelease.Vcs => ? 
       vcs: Mercurial <- get (releaseVcs in Compile) 
          ^

是否有可能模式匹配的類型的表達?

+1

的[爲什麼Scala的模式MACHING不爲類型匹配迴路工作?]可能的複製(http://stackoverflow.com/questions/11394034/why-scalas-pattern-maching-does-not-for-for-loops-for-type-matching) –

回答

2

,如果你使用的forcollect,而不是它真的很簡單:

trait A 
case class B(x: Int) extends A 
case class C(y: Int) extends A 

val someB: Option[A] = Some(B(2)) 
val someC: Option[A] = Some(C(2)) 
val noneA: Option[A] = None 
someB.collect { case n: B => n } // Some(B(2)) 
someC.collect { case n: B => n } // None 
noneA.collect { case n: B => n } // None 
+0

這就是我所做的,但理解對我來說感覺更清潔(至少如果它工作:),因爲單個案例的模式匹配看起來很尷尬。 – gregsymons

0

您可以使用一個醜陋的測試:

for { 
    vcs <- maybeVcs 
    if vcs.instanceof[Mercurial] 
} yield vcs 
1

,這種模式匹配不起作用的事實實際上是一個錯誤(至少它不符合規範)。請參閱https://issues.scala-lang.org/browse/SI-900

但是,有一個簡單的解決方法。 某處定義下列對象:

object Id { unapply[T](x:T) = Some(x) } 

現在你可以使用Id(x)作爲匹配一切的模式匹配,只是結合x到不管它匹配。所以基本上是一個毫無意義的構造,因爲Id(pattern)pattern相同。

但是,它有一個影響:Id(...)中的類型註釋不會被解釋爲類型註釋,而是類型模式。因此

for { 
    Id(vcs: Mercurial) <- maybeVcs 
} yield vcs 

會有你想要的效果。 (而不同於Bob's answer,整體表現將會有型Seq[Mercurial]而不是Seq[Vcs]。)