2016年7月10日 星期日

[Scala IA] The Basics : Ch2. Getting Started - Pattern matching

Pattern matchingPattern matching is another functional programming concept introduced in Scala. To start with, Scala pattern matching looks similar to switch case in Java. The example in the following listing, showing the similarity between Scala and Java, takes an integer and prints its ordinal number. - Listing 2.2 An ordinal class written in Java

Here the argument of the program is parsed to the integer value, and the ordinal method returns the ordinal text of a given number. Right now, it only knows how to handle numbers from 1 to 10. The following listing shows the same example in Scala. - Listing 2.3 An ordinal class in Scala

Here you’re doing something similar to the previous Java example: taking an input integer value from a command like args and determining the ordinal value of the number. Because Scala can also be used as a scripting language, you don’t have to define an entry point like the main method. And you no longer need to provide a break for each case because in Scala you can’t overflow into other case clauses (causing multiple matches) as in Java, and there’s no default statement. In Scala, default is replaced with case _ to match everything else.

The wildcard case is optional and works like a safe fallback option. If you remove it, and none of the existing cases match, you get a match error:

This is great because it tells you that you’re missing a case clause, unlike in Java, where if you remove the default and none of the existing cases match, it ignores it without providing any sort of feedback.

The similarity between Java and Scala pattern matching ends here because Scala takes pattern matching to the next level. In Java you can only use a switch statement with primitives and enums, but in Scala you can pattern match strings and complex values, types, variables, constants, and constructors. More pattern-matching concepts are in the next chapter, particularly constructor matching, but look at an example of a type match. The following example defines a method that takes an input and checks the type of the given object:

In this example you’re using a Scala type pattern consisting of a variable and a type. This pattern matches any value matched by the type pattern—in this case, String, List[AnyRef], Array[AnyRef], and java.util.Date. When the pattern matches with the type, it binds the variable name to the value. You could do that in Java using the instanceof operator and casting, but this is a more elegant solution. Save this method into the file printType.scala and load the file into the Scala REPL:

Scala also allows the infix operation pattern, in which you can specify an infix operator in your pattern. In the infix style, operators are written between the operands—for example, 2 + 2. In the following example, you’re extracting the first and the second elements from the List:

Here you’re matching 1 to f, 2 to s, and 3 and 4 to the rest of the variables. Think of it as what it will take to create a List of 1, 2 ,3, and 4 from the expression f :: s :: rest, and then this will make more sense. Sometimes you need to have a guard clause along with the case statement to have more flexibility during pattern matching. In the following example you’re determining the range in which the given number belongs:

With this new information, revisit the ordinal problem. The previous Scala ordinal example supported only 1 to 10, but the following listing implements that for all integers. - Listing 2.4 Ordinal2.scala reimplemented

Here in the new implementation of ordinal you’re using range, which is a collection of integer values between a given start and end. The expression 10 to 20 is 10.to(20) (remember that methods can be used as infix operators). You’re calling the to method in RichInt, and it creates an inclusive range (scala.collection.immutable.Range.Inclusive). You’re calling the contains method on the range to check whether the number belongs to the range. In the last case you’re mapping all the numbers below 10 and beyond 20 to a new variable called rest. This is called variable pattern matching in Scala. You can access elements of a List like array using index positions in the List. You’ll revisit pattern matching in chapter 3 after looking at case classes. It’s time to move on to the last topic of this chapter: exception handling.