case Tuple2(one, two)
the methods Tuple2.unapply and Tuple2.unapplySeq are called to see if that case can match the input. If one of methods return a Some(...) object then the case is considered to be a match. These methods are called Extractor methods because they essentially decompose the object into several parameters. I will cover unapplySeq later.
Examples are the best way to illustrate the issue:
- // The unapply method of this object takes a string and returns an Option[String]
- // This means that the value being matched must be a string and the value extracted is also a string
- scala> object SingleParamExtractor {
- | def unapply(v:String):Option[String] = if(v.contains("Hello")) Some("Hello") else None
- | }
- defined module SingleParamExtractor
- // this Will match since the extractor will return a Some object
- scala> "Hello World" match { case SingleParamExtractor(v) => println(v) }
- Hello
- // this will not match and therefore an exception will be thrown
- scala> "Hi World" match { case SingleParamExtractor(v) => println(v) }
- scala.MatchError: Hi World
- at .
(:7) - at .
() - at RequestResult$.
(:3) - at RequestResult$.
() - at RequestResult$result(
) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
- at sun.reflect.DelegatingMethodAccessorImpl.invok...
- // This extractor converts the string to an int if possible.
- scala> object ConvertToInt{
- | def unapply(v:String):Option[Int] = try{ Some(v.toInt) } catch { case _ => None }
- | }
- defined module ConvertToInt
- scala> "10" match { case ConvertToInt(i) => println(i)}
- 10
- // If you want to extract multiple elements you return an Option that contains a Tuple.
- // In this example we divide the string into two parts if it has a space
- scala> object MultipleParamExtractor {
- | def unapply(v:String):Option[(String,String)] = (v indexOf ' ') match {
- | case x if (x>0) => Some ((v take x, v drop x+1))
- | case _ => None
- | }
- | }
- defined module MultipleParamExtractor
- scala> "hello everyone :)" match { case MultipleParamExtractor(one, two) => println(one,two) }
- (hello,everyone :))
- // Any object with a unapply method can be used it does not have to be defined as an object
- // So if you have a class of extractors that needs to be parameterized you can
- // create a class and use instances of that class for matching
- scala> class Splitter(sep:Char){
- | def unapply(v:String):Option[(String,String)] = (v indexOf sep) match {
- | case x if (x>0) => Some ((v take x, v drop x+1))
- | case _ => None
- | }
- | }
- defined class Splitter
- // Remember that we need the matching object start with an uppercase
- // See http://daily-scala.blogspot.com/2009/09/case-sensitive-matching.html
- // for details
- scala> val SplitOnComma = new Splitter (',')
- SplitOnComma: Splitter = Splitter@15eb9b0d
- // How cool now can create splitters for all sorts of things
- scala> "1,2" match { case SplitOnComma(one,two) => println(one,two)}
- (1,2)
- // All extractors can also be used in assignments
- scala> val SplitOnComma(one,two) = "1,2"
- one: String = 1
- two: String = 2
Hi there, awesome site. I thought the topics you posted on were very interesting. I tried to add your RSS to my feed reader and it a few. take a look at it, hopefully I can add you and follow.
ReplyDeleteAwesome !
ReplyDeleteThanks for showing a very useful and simple use case for Scala extractor / unapply! I've been learning how to use this powerful construct.
cool, especially the thing about instances of a class with unapply method
ReplyDelete