J'ai le code suivant qui fonctionne récursivement sur chaque élément d'une liste
def doMatch(list: List[Int]): Unit = list match {
case last :: Nil => println("Final element.")
case head :: tail => println("Recursing..."); doMatch(tail)
}
Maintenant, en ignorant que cette fonctionnalité est disponible via filter () et foreach (), cela fonctionne très bien. Cependant, si j'essaye de le changer pour accepter n'importe quel Seq [Int], je rencontre des problèmes:
Voici à quoi je pense que le code devrait ressembler, sauf qu'il ne fonctionne pas:
def doMatch(seq: Seq[Int]): Unit = seq match {
case last +: Seq() => println("Final element.")
case head +: tail => println("Recursing..."); doMatch(tail)
}
Edit: Tant de bonnes réponses! J'accepte la réponse d'agilesteel car la sienne a été la première à noter que :: n'est pas un opérateur dans mon exemple, mais une classe de cas et donc la différence.
Il y a deux ::
(Contre prononcé) à Scala. L'un est un opérateur défini dans class List
Et l'autre est un classe (sous-classe de List
), qui représente une liste non vide caractérisée par une tête et une queue.
head :: tail
Est un modèle constructeur, qui est modifié syntaxiquement à partir de ::(head, tail)
.
::
Est une classe de cas, ce qui signifie qu'un objet extracteur lui est défini.
Une sorte de tricherie, mais voilà:
def doMatch(seq: Seq[Int]): Unit = seq match {
case Seq(x) => println("Final element " + x)
case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs)
}
Ne me demandez pas pourquoi xs*
ne fonctionne pas ...
Depuis les ides de mars 2012, cela fonctionne en 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.
Plus généralement, deux objets tête/queue et init/dernière décomposition différents en miroir append/prepend ont été ajoutés pour Seq
dans 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)
Vous pouvez réellement définir un objet pour que +:
Fasse exactement ce que vous cherchez:
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)
Ensuite, votre code fonctionne exactement comme prévu.
Cela fonctionne car h +: t
Est équivalent à +:(h,t)
lorsqu'il est utilisé pour la correspondance de patten.
Je ne pense pas qu'il existe un support de correspondance de motifs pour les séquences arbitraires dans la bibliothèque standard. Vous pouvez le faire sans correspondance de motifs:
def doMatch(seq: Seq[Int]) {
if (seq.size == 1) println("final element " + seq(0)) else {
println("recursing")
doMatch(seq.tail)
}
}
doMatch(1 to 10)
Vous pouvez cependant définir vos propres objets extracteurs. Voir 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)
}
}
}