scala case classes questions

眉间皱痕 提交于 2019-12-22 04:19:13

问题


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 => ....

?


回答1:


     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



回答2:


It's detailed in page 301 of Programming in Scala, About pattern matching on Lists.

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 as p op q is equivalent to op(p, q). That is, the infix operator op is treated as a constructor pattern. In particular, a cons pattern such as x :: 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 named scala.:: and is exactly the class that builds non-empty lists.




回答3:


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.




回答4:


The text cited by eed3si9n is on p. 331 in the PDF-edition of "Programming in Scala" (1st ed.)



来源:https://stackoverflow.com/questions/1521011/scala-case-classes-questions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!