I have two questions regarding the '::' case class.
:: can be used as
case head :: tail => ...
How does it work? Meaning, what is exactly the flow that Scala uses to match a List instance with the :: case class? Given that I have a class MyClass, with operator op, can I create a case class named op that I can use as:
case foo op bar => ....
?
scala> abstract class Stack {
| def push(n :Int):Stack
| }
defined class Stack
scala> final case class push(st :Stack,hd :Int) extends Stack {
| override def push(n :Int):Stack = new push(this,n)
| }
defined class push
scala> object NullStack extends Stack {
| override def push(n :Int):Stack = new push(null,n)
| }
defined module NullStack
scala> val s = NullStack.push(1).push(2)
s: Stack = push(push(null,1),2)
scala> def test(s :Stack) = s match { case st push i => println(st +"push " + i) }
test: (Stack)Unit
scala> test(s)
push(null,1)push 2
It's detailed in page 301 of Programming in Scala , About pattern matching on List
s.
The "cons" pattern
x :: xs
is a special case of an infix operation pattern. You know already that, when seen as an expression, an infix operation is equivalent to a method call. For patterns, the rules are different: When seen as a pattern, an infix operation such asp op q
is equivalent toop(p, q)
. That is, the infix operatorop
is treated as a constructor pattern. In particular, a cons pattern such asx :: xs
is treated as::(x, xs)
. This hints that there should be a class named::
that correspond to the pattern constructor. Indeed there is such a class. It is namedscala.::
and is exactly the class that builds non-empty lists.
Actually, the fact that :: is a case class is only half of the answer. The reason this works in pattern matching is that there is an extractor for object ::, which is generated automatically when a case class is defined. Conveniently, ::.unapply returns a List, because :: extends List. If you want to use the same trick for Lists, though, you won't be able to extend List, because it's final . What you can do is define an object with the appropriate unapply method, which has the expected return signature. For instance, to match the last element of a list, you can do:
object ::> {def unapply[A] (l: List[A]) = Some( (l.init, l.last) )}
List(1, 2, 3) match {
case _ ::> last => println(last)
}
(1 to 9).toList match {
case List(1, 2, 3, 4, 5, 6, 7, 8) ::> 9 => "woah!"
}
(1 to 9).toList match {
case List(1, 2, 3, 4, 5, 6, 7) ::> 8 ::> 9 => "w00t!"
}
The extractor must return an Option, which contains a tuple of the two deconstructed elements.
The text cited by eed3si9n is on p. 331 in the PDF-edition of "Programming in Scala" (1st ed.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.