为什么我不能匹配流?

时间:2017-03-02 01:54:00

标签: scala

具体做法是:

scala> def f(n: Seq[Any]) = n match { 
     case Nil => "Empty" 
     case h :: t => "Non-empty" 
}
f: (n: Seq[Any])String

scala> f(Stream())
res1: String = Empty

scala> f(List(1))
res17: String = Non-empty

scala> f(Stream(1))
scala.MatchError: Stream(1, ?) (of class scala.collection.immutable.Stream$Cons)
  at .f(<console>:13)
  ... 33 elided

还有很多其他方法可以实现这一点,但在编写代码时,代码是静态安全的,并且在运行时失败。发生了什么事?

3 个答案:

答案 0 :(得分:2)

对于Stream concat 符号应为#::模式匹配应为:

  def f(n: Seq[Any]) = n match {
    case Nil => "Empty"
    case h :: t => "Non-empty"
    case h #:: t => "Non-empty stream"
  }
::

适用于List / Seq类型(List扩展自Seq :),请参阅:

final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {

答案 1 :(得分:1)

您只能使用::来解构List而不是Stream。由于您提供的StreamList不匹配,因此您获得了MatchError。如果您希望f使用该类型的匹配(提取器)来支持流,则可以使用#::

def f(n: Seq[Any]) = n match {
  case Nil => "Empty"
  case h :: t => "Non-empty"
  case h #:: t => "Non-empty"
}

一般来说,这种方法非常脆弱,因为上面显示的两种提取器类型只适用于这两种类型的Seq。其他人可能会休息如果您关心的是确定Seq是否为空,那么只需使用n.nonEmptyn.isEmpty并处理Boolean结果即可。否则,尝试在未密封的特征上提供详尽的匹配肯定会失败。

您还可以使用Seq提取器:

def f(n: Seq[Any]) = n match { 
  case Nil => "Empty" 
  case Seq(_*) => "Non-empty" 
}

答案 2 :(得分:0)

虽然其他答案正确显示了Stream特定的提取程序#::,但Seq存在一个提取程序(以及从SeqLike派生的任何内容) - 它是+:,这适用于List(作为::)和Stream(作为`#::)。使用此提取器,您可以轻松编写适用于以下两者的函数:

def f(n: Seq[Any]) = n match { 
  case h +: t => "Non-empty" 
  case _ => "Empty" 
}

另见Scala pattern matching on sequences other than Lists