Scala pattern matching on sequences other than Lists

As of the ides of March 2012, this works in 2.10+:

  def doMatch(seq: Seq[Int]): Unit = seq match {
    case last +: Seq() => println("Final element.")
    case head +: tail  => println("Recursing..."); doMatch(tail)
  }                                               //> doMatch: (seq: Seq[Int])Unit

  doMatch(List(1, 2))                             //> Recursing...
                                                  //| Final element.

More generally, two different head/tail and init/last decomposition objects mirroring append/prepend were added for Seq in SeqExtractors:

List(1, 2) match { case init :+ last => last } //> res0: Int = 2                                              
List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2)                                               
Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2                                              
Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)

Kind of cheating, but here it goes:

def doMatch(seq: Seq[Int]): Unit = seq match {
  case Seq(x) => println("Final element " + x)
  case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs)
}

Don't ask me why xs* doesn't work...


There are two :: (pronounced cons) in Scala. One is an operator defined in class List and one is a class (subclass of List), which represents a non empty list characterized by a head and a tail.

head :: tail is a constructor pattern, which is syntactically modified from ::(head, tail).

:: is a case class, which means there is an extractor object defined for it.


You can actually define an object for +: to do exactly what you are looking for:

object +: { 
  def unapply[T](s: Seq[T]) = 
    if(s.nonEmpty)
      Some(s.head, s.tail) 
    else
      None
}

scala> val h +: t = Seq(1,2,3)
h: Int = 1
t: Seq[Int] = List(2, 3)

Then your code works exactly as expected.

This works because h +: t is equivalent to +:(h,t) when used for patten matching.