列表以外的序列上的 Scala 模式匹配
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6807540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala pattern matching on sequences other than Lists
提问by Zecrates
I have the following code which recursively operates on each element within a List
我有以下代码递归操作列表中的每个元素
def doMatch(list: List[Int]): Unit = list match {
case last :: Nil => println("Final element.")
case head :: tail => println("Recursing..."); doMatch(tail)
}
Now, ignoring that this functionality is available through filter()and foreach(), this works just fine. However, if I try to change it to accept any Seq[Int], I run into problems:
现在,忽略此功能可通过filter()和foreach() 获得,这很好用。但是,如果我尝试将其更改为接受任何Seq[Int],则会遇到问题:
- Seq doesn't have ::, but it does have +:, which as I understand is basically the same thing. If I try to match on head +: tail however, the compiler complains 'error: not found: value +:'
- Nil is specific to List, and I'm not sure what to replace it with. I'm going to try Seq() if I ever get past the previous problem
- Seq 没有 ::,但它有 +:,据我所知,这基本上是一样的。但是,如果我尝试在 head +: tail 上进行匹配,则编译器会抱怨“错误:未找到:值 +:”
- Nil 特定于 List,我不确定用什么来替换它。如果我解决了之前的问题,我将尝试 Seq()
Here is how I think the code should look, except it doesn't work:
这是我认为代码应该看起来的样子,除了它不起作用:
def doMatch(seq: Seq[Int]): Unit = seq match {
case last +: Seq() => println("Final element.")
case head +: tail => println("Recursing..."); doMatch(tail)
}
Edit: So many good answers! I'm accepting agilesteel's answer as his was the first that noted that :: isn't an operator in my example, but a case class and hence the difference.
编辑:这么多好的答案!我接受了agilesteel 的回答,因为他是第一个指出 :: 在我的示例中不是运算符,而是案例类,因此是不同的。
采纳答案by agilesteel
There are two ::(pronounced cons) in Scala. One is an operator defined in class Listand one is a class(subclass of List), which represents a non empty list characterized by a head and a tail.
::Scala 中有两个(发音为 cons)。一个是定义在中的运算符class List,一个是一个类( 的子类List),它表示一个以头和尾为特征的非空列表。
head :: tailis a constructor pattern, which is syntactically modified from ::(head, tail).
head :: tail是一个构造函数模式,它在语法上是从::(head, tail).
::is a case class, which means there is an extractor object defined for it.
::是一个案例类,这意味着为它定义了一个提取器对象。
回答by Landei
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...
不要问我为什么xs*不工作...
回答by yakshaver
As of the ides of March 2012, this works in 2.10+:
截至 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.
More generally, two different head/tail and init/last decomposition objects mirroring append/prepend were added for Seqin SeqExtractors:
更一般地说,Seq在SeqExtractors中添加了两个不同的 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)
回答by dhg
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 +: tis equivalent to +:(h,t)when used for patten matching.
这是有效的,因为h +: t等效于+:(h,t)用于模式匹配时。
回答by Kim Stebel
I don't think there is pattern matching support for arbitrary sequences in the standard library. You could do it with out pattern matching though:
我认为标准库中没有对任意序列的模式匹配支持。你可以不用模式匹配来做到这一点:
def doMatch(seq: Seq[Int]) {
if (seq.size == 1) println("final element " + seq(0)) else {
println("recursing")
doMatch(seq.tail)
}
}
doMatch(1 to 10)
You can define your own extractor objects though. See http://www.scala-lang.org/node/112
不过,您可以定义自己的提取器对象。见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)
}
}
}
回答by user unknown
A simple tranformation from Seq to List would do the job:
从 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)

