简体   繁体   English

是否可以在Scala中的类型上进行模式匹配以进行表达?

[英]Is it possible to pattern match on type in a Scala for expression?

I'm trying to use a for expression to map over an Option, but I only want to match if the contents of the Option are of a specific type. 我正在尝试使用for表达式来映射Option,但我只想在Option的内容属于特定类型时进行匹配。 What I thought would work is this: 我认为可以的是这样的:

for {
  vcs: Mercurial <- maybeVcs
} yield vcs

But that yields the following compile error: 但这会产生以下编译错误:

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

Is it possible to pattern match on type in a for expression? 是否可以在for表达式的类型上进行模式匹配?

It's really straightforward if you use collect instead of for : 如果您使用collect而不是for这真的很简单:

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

The fact that this pattern match does not work is actually a bug (at least its not in accordance with the spec). 这种模式匹配不起作用的事实实际上是一个错误(至少与规范不符)。 See https://issues.scala-lang.org/browse/SI-900 . 参见https://issues.scala-lang.org/browse/SI-900

However, there is a simple workaround. 但是,有一个简单的解决方法。 Define somewhere the following object: 在某处定义以下对象:

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

Now you can use Id(x) as a pattern match that matches everything, and just binds x to whatever it matched. 现在,您可以将Id(x)用作匹配所有内容的模式匹配项,并将x绑定到任何匹配项。 So basically a pointless construct, since Id(pattern) is the same as pattern . 所以基本上没有意义的构造,因为Id(pattern)pattern相同。

However, it has one effect: A type annotation inside Id(...) will not be interpreted as a type annotation, but as a type pattern. 但是,它具有一种效果: Id(...)内部的类型注释将不解释为类型注释,而是解释为类型模式。 Thus 从而

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

will have the effect you desire. 将达到您想要的效果。 (And differently from Bob's answer , the overall expression will have type Seq[Mercurial] and not Seq[Vcs] .) (与Bob的回答不同,整个表达式的类型将为Seq[Mercurial]而不是Seq[Vcs] 。)

You can use an ugly test: 您可以使用一个丑陋的测试:

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

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

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