Pattern Matching in Scala

5,436 views

Published on

An igNite presentation for DOSUG igNite, October 5th, 2010

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,436
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
35
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Pattern Matching in Scala

  1. 1. Derek Chen-BeckerPattern Matching in Scala DOSUG IgNite Presentation October 5th, 2010
  2. 2. I Believe Youve Met Mr. “switch”...switch(foo) {case 1 : doBar("two"); break;case 2 : doBar("one"); break;default: doBar("forty-two");} I can feel the excitement! 2
  3. 3. Scala Merges OO and Functional Features 3
  4. 4. Scalas “match” Like “switch” var foo : Int = 5 foo match { case 1 => doBar("two") case 2 => { doBar("one"); doBar("two") } case _ => doBar("lemon curry?") } No “break”. Each clause is self-contained Matches are tried in order, first match wins What in the heck is this “_” nonsense? 4
  5. 5. Match Against Broader Range of Types def literalMatch (in: Any) { in match { case 1 => doBar("One") case "test" => doBar("test") case x => doBar("x") case 2.2f => doBar("float") case _ => doBar("lemon curry?") } } You can think of this like nested “if” statements 5
  6. 6. Alternate Patterns def literalMatch (in: Any) { in match { case 1 | 2 | 3 => doBar("One to three") case "this" | "that" => doBar("the other") case _ => doBar("lemon curry?") } } “|” allows clause to match multiple values 6
  7. 7. Binding Variables in Matches def literalMatch (in: Any) { in match { case n @ (1 | 2 | 3) => doBar("1-3:" + n) case t @ ("this" | "that") => DoBar(t + " and the other") case x => doBar("We defaulted on " + x) } } You can bind a complex pattern with “x @ pattern” Just a variable as a pattern matches anything 7
  8. 8. Matching on Typedef typeMatch (in: Any) { in match { case i : Int => doBar("Int : " + i) case s : String => doBar(s) case _ => // NOOP }} 8
  9. 9. Matching on Generic Typesdef typeMatch (in: Any) { in match { case ls : List[String] => doBar("danger!") case li : List[Int] => doBar("never happens") case _ => // NOOP }} You cant match on generic types because of erasure The compiler will warn about unchecked conversions if you do this 9
  10. 10. Guards Permit Fine-Grained Selection 10
  11. 11. <Ahem> Guards Permit Fine-Grained Selectiondef fifenator (in: Any) { in match { case i : Int if i > 12 && i < 47 => doBar("Int : " + i) case s : String if s.startsWith("DOSUG") => doBar(s) case _ => // NOOP }} A guard is just a conditional clause for the match Because the type is being matched on the left, you have direct access to the type methods and fields without casts 11
  12. 12. A Brief Digression into Case Classescase class Character(show : String, name : String) A Case Class is a special type of class that automatically adds methods for equals, hashcode, toString, and PATTERN MATCHING 12
  13. 13. A Brief Digression into Case Classesdef tvTime (c : Character) = c match { case Character(title, "Fred") => doBar("Fred from " + title) case Character("Flintstones", n) => doBar(n) case c @ Character(_,_) => doBar(c.name)} Constructor arguments automatically become properties that you can match against 13
  14. 14. But Wait, Theres More! Custom Extractors Sealed class hierarchy enforcement Cleans Tough Stains! Gentle on Hands! Repels Cougars! And more! 14
  15. 15. Sealed Hierarchy Enforcementsealed abstract class EntityType(val name : String)case class Animal(n : String) extends EntityType(n)case class Vegetable(n : String) extends EntityType(n)case class Mineral(n : String) extends EntityType(n) “sealed” indicates that all direct subclasses are defined in the same source file Provides the compiler with a guaranteed bound on the type hierarchy: scala> def questionOne(t : EntityType) = t match { | case Animal(name) => println("Animal: " + name) | case Vegetable(name) => println("Veggie: " + name) |} <console>:8: warning: match is not exhaustive! missing combination Mineral def questionOne(t : EntityType) = t match { 15
  16. 16. Custom Extraction Basicsobject Something { def unapply(input : Foo) : Option[Bar] = { if (input.bar) Some(input.toBar) else None }} An “object” is a singleton in the VM, defined as you would a class Methods on an object equivalent to “static” methods in Java 16
  17. 17. Custom Extraction Basicsobject Something { def unapply(input : Foo) : Option[Bar] = { if (input.bar) Some(input.toBar) else None }} Option is a predefined Scala type that has only two subclasses: Some and None A Some holds a typed value 17
  18. 18. Custom Extraction Basicsobject Something { def unapply(input : Foo) : Option[Bar] = { if (input.bar) Some(input.toBar) else None }} The “unapply” method holds special significance to the compiler Is used to attempt an extraction/match from a given input Returning Some(something) indicates a match Returning None indicates no match 18
  19. 19. Custom Extraction: IP Addressobject Octet { def unapply(input : String) = try { val octet = input.toInt if (octet >= 0 && octet < 256) Some(octet) else None } catch { case _ => None }} First we just define what an octet in an IP is: An Int... Between 0 and 255 19
  20. 20. Custom Extraction: IP Addressobject IP {def unapplySeq(input : String) : Option[Seq[Int]] = input.split(.) match { case Array(Octet(a), Octet(b), Octet(c), Octet(d)) => Some(List(a,b,c,d)) case _ => None }} “unapplySeq” allows us to return a sequence of results on a match We nest our Octet matcher to match each IP component 20
  21. 21. Custom Extraction in Actionscala> def sumIP (address : String) = address match { | case IP(7, b, c, d) => println("Jackpot!"); Some(7 + b + c + d) | case IP(a,b,c,d) ⇒ Some(a + b + c + d) | case _ => None |}sumIP: (address: String)Option[Int]scala> sumIP("12.25.233.61")res5: Option[Int] = Some(331)scala> sumIP("12.25.233")res6: Option[Int] = Nonescala> sumIP("7.25.233.61")Jackpot!res7: Option[Int] = Some(326) 21
  22. 22. Still With Me? 22
  23. 23. 23

×