Scala模式匹配列表以外的序列

我有以下代码recursion操作列表中的每个元素

def doMatch(list: List[Int]): Unit = list match { case last :: Nil => println("Final element.") case head :: tail => println("Recursing..."); doMatch(tail) } 

现在,忽略这个function可以通过filter()foreach() ,这工作得很好。 但是,如果我试图改变它接受任何Seq [Int] ,我遇到了问题:

  • Seq没有::,但它确实有+:,据我所知基本上是一样的东西。 如果我试图匹配head +:tail,但是,编译器会抱怨错误:not found:value +:'
  • 无特定于列表,我不知道如何replace它。 如果我经历过前面的问题,我会尝试Seq()

这是我认为代码应该看起来如何,除非它不工作:

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

编辑:这么多好的答案! 我接受agilesteel的答案,因为他是第一个注意到::在我的例子中不是一个操作符,而是一个案例类,因此是差异。

Scala中有两个:: :(发音为cons)。 一个是在class List定义的运算符,另一个是一个类 ( List子类),它表示一个以头部和尾部为特征的非空列表。

head :: tail是一个构造函数模式,它在语法上从::(head, tail)

::是一个case类,这意味着有一个为其定义的提取器对象。

有点作弊,但这里是:

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

不要问我为什么xs*不工作…

作为2012年3月的IDE,这个工作在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. 

更一般地说,在SeqExtractors中为Seq添加了两个不同的head / tail和init / last分解对象:append / prepend。

 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) 

你实际上可以为+:定义一个对象+:做你正在寻找的东西:

 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) 

然后你的代码完全按照预期工作。

这是+:(h,t)因为当用于模式匹配时+:(h,t) h +: t相当于+:(h,t)

我不认为标准库中的任意序列有模式匹配支持。 你可以通过模式匹配来实现:

  def doMatch(seq: Seq[Int]) { if (seq.size == 1) println("final element " + seq(0)) else { println("recursing") doMatch(seq.tail) } } doMatch(1 to 10) 

你可以定义你自己的提取器对象。 见http://www.scala-lang.org/node/112

 object SEQ { def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = { if (s.size == 0) None else { Some((s.head, s.tail)) } } } def doMatch(seq: Seq[Int]) { seq match { case SEQ(head, Seq()) => println("final") case SEQ(head, tail) => { println("recursing") doMatch(tail) } } } 

从Seq到List的简单转换就可以完成这项工作:

 def doMatch (list: List[Int]): Unit = list match { case last :: Nil => println ("Final element.") case head :: tail => println ("Recursing..."); doMatch (tail) case Nil => println ("only seen for empty lists") } def doMatchSeq (seq: Seq[Int]) : Unit = doMatch (seq.toList) doMatch (List(3, 4, 5)) doMatchSeq (3 to 5)