{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Tour of Scala
\n", "\n", "\n", "# Extractor Objects\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sukyoung\n" ] }, { "data": { "text/plain": [ "\u001b[32mimport \u001b[39m\u001b[36mscala.util.Random\n", "\n", "\u001b[39m\n", "defined \u001b[32mobject\u001b[39m \u001b[36mCustomerID\u001b[39m\n", "\u001b[36mcustomer1ID\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Sukyoung---5392557361748469708\"\u001b[39m" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import scala.util.Random\n", "\n", "object CustomerID {\n", "\n", " def apply(name: String) = s\"$name--${Random.nextLong}\"\n", "\n", " def unapply(customerID: String): Option[String] = {\n", " val stringArray: Array[String] = customerID.split(\"--\")\n", " if (stringArray.tail.nonEmpty) Some(stringArray.head) else None\n", " }\n", "}\n", "\n", "val customer1ID = CustomerID(\"Sukyoung\") // Sukyoung--23098234908\n", "customer1ID match {\n", " case CustomerID(name) => println(name) // prints Sukyoung\n", " case _ => println(\"Could not extract a CustomerID\")\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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) => println(name)`, we're calling the unapply method.\n", "\n", "Since a value definition can use a pattern to introduce a new variable, an extractor can be used to initialize the variable, where the unapply method supplies the value." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Nico\n" ] }, { "data": { "text/plain": [ "\u001b[36mcustomer2ID\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Nico---4359663507340171480\"\u001b[39m\n", "\u001b[36mname\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Nico\"\u001b[39m" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val customer2ID = CustomerID(\"Nico\")\n", "val CustomerID(name) = customer2ID\n", "println(name) // prints Nico" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is equivalent to `val name = CustomerID.unapply(customer2ID).get`." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mname2\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"\"\u001b[39m" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val CustomerID(name2) = \"--asdfasdfasdf\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If there is no match, a `scala.MatchError` is thrown:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "ename": "", "evalue": "", "output_type": "error", "traceback": [ "\u001b[31mscala.MatchError: -asdfasdfasdf (of class java.lang.String)\u001b[39m\n ammonite.$sess.cmd3$Helper.Tour of Scala
\n", "" ] } ], "metadata": { "kernelspec": { "display_name": "Scala (2.13)", "language": "scala", "name": "scala213" }, "language_info": { "codemirror_mode": "text/x-scala", "file_extension": ".scala", "mimetype": "text/x-scala", "name": "scala", "nbconvert_exporter": "script", "version": "2.13.1" } }, "nbformat": 4, "nbformat_minor": 4 }