It’s a little hard to get into useful programming or scripting with Scala without the loops and ifs. Well, your wait is over. In Scala, if and else blocks work as they do in any other programming language. If the expression inside the ifevaluates to true, then the if block gets executed; otherwise, the else block is executed. The interesting part about Scala is that every statement is an expression, and its value is determined by the last expression within the statement. Assigning a value depending on some condition in Scala could look like this:
- val someValue = if(some condition) value1 else value2
For-comprehensions
A for-comprehension in Scala is like a Swiss Army knife: you can do many things with it using basic simple elements. The for expression in Scala consists of a for keyword followed by one or more enumerators surrounded by parentheses and followed by an expression block or yield expression (see figure 2.2).
Before I go into yield expression, let’s look into the more traditional form of the for loop. The common pattern used in a for loop is to iterate through a collection. To print all the files in a directory that end with the .scala extension, for example, you have to do something like the following:
- val files = new java.io.File(".").listFiles
- for(file <- files="" nbsp="" span="">->
- val filename = file.getName
- if(fileName.endsWith(".scala")) println(file)
- }
The only thing that looks different from for loops in Java or C# is the expression file <- files="" font="">. In Scala this is called a generator, and the job of a generator is to iterate through a collection. The right side of the <- b="">-> represents the collection—in this case, files. For each element in the collection (file in this case) it executes the for block. This is similar to the way you define a for loop in Java: ->
- for(File file: files) {
- String filename = file.getName();
- if(filename.endsWith(".scala")) System.out.println(file);
- }
- for(
- file <- files="" nbsp="" span="">->
- fileName = file.getName;
- if(fileName.endsWith(".scala"))
- ) println(file)
As mentioned earlier, it’s possible to specify more than one generator in a Scala for loop control. The following example executes the loop for each generator and adds them:
The generators in this case are aList and bList, and when you have multiple generators, each generator is repeated for the other generator. When a = 1 for each value of b, that is, b = 4, b = 5, b = 6, the loop will be executed, and so on. I used curly braces to surround the for expression, but you don’t have to; you could use (). I tend to use curly braces when I have more than one generator and guard clause.
The for-comprehension in Scala comes in two flavors. You’ve already seen one form in the previous examples: the imperative form. In this form you specify the statements that will get executed by the loop, and it doesn’t return anything. The other form of for-comprehension is called the functional form (sometimes it’s also called sequence comprehension). In the functional form, you tend to work with values rather than execute statements, and it does return a value. Look at the same example in functional form:
Instead of printing the value of a + b, you’re returning the value of the addition from the loop using the yield keyword. You’re using the same aList and bList instances in the loop control, and it returns the result as a List. Now if you want to print the result, as in the previous example, you have to loop through the result List:
It does look like the functional form is more verbose than the imperative form, but think about it. You’ve separated the computation (the adding of two numbers) from how you’re using it—in this case, printing the result. This improves the reusability and compatibility of functions or computations, which is one of the benefits of functional programming. In the following example you reuse the result produced by the for yield loop to create an XML node:
The mkString is a method defined in scala.collection.immutable.List. It takes each element in the List and concatenates each element with whatever separator you provide—in this case, a comma. Even though it doesn’t make sense, what if you try to print inside the yield expression? What will happen? Remember, everything in Scala is an expression and has a return value. If you try the following, you’ll still get a result, but the result won’t be useful because it will be a collection of units. A unit is the equivalent of void in Java, and it’s the result value of a println function used inside the yield expression:
You’ve only scratched the surface of for-comprehension, and I come back to this in chapter 4 to examine functional data structures, so hold on to your inquisitiveness until chapter 4 (or jump to that chapter). The next section moves into another functional concept: pattern matching.
沒有留言:
張貼留言