{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Tour of Scala
\n", "\n", "\n", "# Pattern Matching\n", "\n", "Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the `switch` statement in Java and it can likewise be used in place of a series of if/else statements.\n", "\n", "## Syntax\n", "A match expression has a value, the `match` keyword, and at least one `case` clause." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[32mimport \u001b[39m\u001b[36mscala.util.Random\n", "\n", "\u001b[39m\n", "\u001b[36mx\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m1\u001b[39m\n", "\u001b[36mres0_2\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"one\"\u001b[39m" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import scala.util.Random\n", "\n", "val x: Int = Random.nextInt(10)\n", "\n", "x match {\n", " case 0 => \"zero\"\n", " case 1 => \"one\"\n", " case 2 => \"two\"\n", " case _ => \"many\"\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `val x` above is a random integer between 0 and 10. `x` becomes the left operand of the `match` operator and on the right is an expression with four cases. The last case `_` is a \"catch all\" case for any number greater than 2. Cases are also called _alternatives_.\n", "\n", "Match expressions have a value." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mfunction\u001b[39m \u001b[36mmatchTest\u001b[39m\n", "\u001b[36mres1_1\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"many\"\u001b[39m\n", "\u001b[36mres1_2\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"one\"\u001b[39m" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def matchTest(x: Int): String = x match {\n", " case 1 => \"one\"\n", " case 2 => \"two\"\n", " case _ => \"many\"\n", "}\n", "matchTest(3) // many\n", "matchTest(1) // one" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This match expression has a type String because all of the cases return String. Therefore, the function `matchTest` returns a String.\n", "\n", "## Matching on case classes\n", "\n", "Case classes are especially useful for pattern matching." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mclass\u001b[39m \u001b[36mNotification\u001b[39m\n", "defined \u001b[32mclass\u001b[39m \u001b[36mEmail\u001b[39m\n", "defined \u001b[32mclass\u001b[39m \u001b[36mSMS\u001b[39m\n", "defined \u001b[32mclass\u001b[39m \u001b[36mVoiceRecording\u001b[39m" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abstract class Notification\n", "\n", "case class Email(sender: String, title: String, body: String) extends Notification\n", "\n", "case class SMS(caller: String, message: String) extends Notification\n", "\n", "case class VoiceRecording(contactName: String, link: String) extends Notification\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Notification` is an abstract super class which has three concrete Notification types implemented with case classes `Email`, `SMS`, and `VoiceRecording`. Now we can do pattern matching on these case classes:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "You got an SMS from 12345! Message: Are you there?\n", "you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123\n" ] }, { "data": { "text/plain": [ "defined \u001b[32mfunction\u001b[39m \u001b[36mshowNotification\u001b[39m\n", "\u001b[36msomeSms\u001b[39m: \u001b[32mSMS\u001b[39m = \u001b[33mSMS\u001b[39m(\u001b[32m\"12345\"\u001b[39m, \u001b[32m\"Are you there?\"\u001b[39m)\n", "\u001b[36msomeVoiceRecording\u001b[39m: \u001b[32mVoiceRecording\u001b[39m = \u001b[33mVoiceRecording\u001b[39m(\n", " \u001b[32m\"Tom\"\u001b[39m,\n", " \u001b[32m\"voicerecording.org/id/123\"\u001b[39m\n", ")" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def showNotification(notification: Notification): String = {\n", " notification match {\n", " case Email(email, title, _) =>\n", " s\"You got an email from $email with title: $title\"\n", " case SMS(number, message) =>\n", " s\"You got an SMS from $number! Message: $message\"\n", " case VoiceRecording(name, link) =>\n", " s\"you received a Voice Recording from $name! Click the link to hear it: $link\"\n", " }\n", "}\n", "val someSms = SMS(\"12345\", \"Are you there?\")\n", "val someVoiceRecording = VoiceRecording(\"Tom\", \"voicerecording.org/id/123\")\n", "\n", "println(showNotification(someSms)) // prints You got an SMS from 12345! Message: Are you there?\n", "\n", "println(showNotification(someVoiceRecording)) // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `showNotification` takes as a parameter the abstract type `Notification` and matches on the type of `Notification` (i.e. it figures out whether it's an `Email`, `SMS`, or `VoiceRecording`). In the `case Email(email, title, _)` the fields `email` and `title` are used in the return value but the `body` field is ignored with `_`.\n", "\n", "## Pattern guards\n", "Pattern guards are simply boolean expressions which are used to make cases more specific. Just add `ifTour 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 }