2015-11-06 65 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]。)