diff --git a/tutorials/tour/_posts/2017-02-13-extractor-objects.md b/tutorials/tour/_posts/2017-02-13-extractor-objects.md index b66efc08eb..f81647d33e 100644 --- a/tutorials/tour/_posts/2017-02-13-extractor-objects.md +++ b/tutorials/tour/_posts/2017-02-13-extractor-objects.md @@ -11,25 +11,43 @@ next-page: sequence-comprehensions previous-page: regular-expression-patterns --- -In Scala, patterns can be defined independently of case classes. To this end, a method named unapply is defined to yield a so-called extractor. An extractor can be thought of as a special method that reverses the effect of applying a particular object on some inputs. Its purpose is to 'extract' the inputs that were present before the 'apply' operation. For instance, the following code defines an extractor [object](singleton-objects.html) Twice. +An extractor object is an object with an `unapply` method. Whereas the `apply` method is like a constructor which takes arguments and creates an object, the `unapply` takes an object and tries to give back the arguments. This is most often used in pattern matching and partial functions. ```tut -object Twice { - def apply(x: Int): Int = x * 2 - def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None +import scala.util.Random + +object CustomerID { + + def apply(name: String) = s"$name--${Random.nextLong}" + + def unapply(customerID: String): Option[String] = { + val name = customerID.split("--").head + if (name.nonEmpty) Some(name) else None + } } -object TwiceTest extends App { - val x = Twice(21) - x match { case Twice(n) => Console.println(n) } // prints 21 +val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908 +customer1ID match { + case CustomerID(name) => println(name) // prints Sukyoung + case _ => println("Could not extract a CustomerID") } ``` -There are two syntactic conventions at work here: +The `apply` method creates a `CustomerID` string from a `name`. The `unapply` does the inverse to get the `name` back. When we call `CustomerID("Sukyoung")`, this is shorthand syntax for calling `CustomerID.apply("Sukyoung")`. When we call `case CustomerID(name) => customer1ID`, we're calling the unapply method. -The pattern `case Twice(n)` will cause an invocation of `Twice.unapply`, which is used to match any even number; the return value of the `unapply` signals whether the argument has matched or not, and any sub-values that can be used for further matching. Here, the sub-value is `z/2` +The unapply method can also be used to assign a value. -The `apply` method is not necessary for pattern matching. It is only used to mimick a constructor. `val x = Twice(21)` expands to `val x = Twice.apply(21)`. +```tut +val customer2ID = CustomerID("Nico") +val CustomerID(name) = customer2ID +println(name) // prints Nico +``` + +This is equivalent to `val name = CustomerID.unapply(customer2ID).get`. If there is no match, a `scala.MatchError` is thrown: + +```tut:fail +val CustomerID(name2) = "--asdfasdfasdf" +``` The return type of an `unapply` should be chosen as follows: @@ -37,6 +55,4 @@ The return type of an `unapply` should be chosen as follows: * If it returns a single sub-value of type T, return an `Option[T]` * If you want to return several sub-values `T1,...,Tn`, group them in an optional tuple `Option[(T1,...,Tn)]`. -Sometimes, the number of sub-values is fixed and we would like to return a sequence. For this reason, you can also define patterns through `unapplySeq`. The last sub-value type `Tn` has to be `Seq[S]`. This mechanism is used for instance in pattern `case List(x1, ..., xn)`. - -Extractors can make code more maintainable. For details, read the paper ["Matching Objects with Patterns"](https://infoscience.epfl.ch/record/98468/files/MatchingObjectsWithPatterns-TR.pdf) (see section 4) by Emir, Odersky and Williams (January 2007). +Sometimes, the number of sub-values is fixed and we would like to return a sequence. For this reason, you can also define patterns through `unapplySeq` which returns `Option[Seq[T]]` This mechanism is used for instance in pattern `case List(x1, ..., xn)`.