Scala for Comprehensions

The term comprehension comes from functional programming. It expresses the idea that we are traversing one or more collections of some kind, “comprehending” what we find, and computing something new from it, often another collection.

1. for loops

Let’s start with a basic for expression:

scala> val list: List[Int] = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)

scala> for (ele <- list) println(ele)
1
2
3
scala> for {ele <- list} println(ele)  // Curly braces also is OK.
1
2
3

Because this form doesn’t return anything, it only performs side effects. These kinds of for comprehensions are sometimes called for loops, analogous to Java for loops.

The expression ele <- list is called a generator expression, so named because it’s generating individual values from a collection. The left arrow operator (<-) is used to iterate through a collection, such as a List.

An informal convention is to use parentheses when the for comprehension has a single expression and curly braces when multiple expressions are used.

2. Guards: Filter Values

We can add if expressions to filter for just elements we want to keep. These expressions are called guards.

One guards

scala> for (ele <- list if ele!= 2) println(ele)
1
3

More than one guards

scala> for (ele <- list if ele!= 2 && ele!=3) println(ele)
1

scala> for (ele <- list if ele!= 2 if ele!=3) println(ele)
1

3. Yielding

What if, rather than printing your filtered collection, you needed to hand it off to another part of your program? The yield keyword is your ticket to generating new collections with for expressions.

scala> for (ele <- list if ele!=2) yield ele
res11: List[Int] = List(1, 3)

When a for comprehension doesn’t use yield, but performs side effects like printing instead, the comprehension is called a for loop, because this behavior is more like the for loops you know from Java and other languages.

4. Expanded Scope and Skip None

(1) Expanded Scope

Another useful feature of Scala’s for comprehensions is the ability to define values inside the first part of your for expressions that can be used in the later expressions., as in this example:

for (ele <- list) println(ele)

Note that ele is an immutable value, but the val keyword isn’t required.

(2) Skip None

If you recall Option, which we discussed as a better alternative to using null, it’s useful to recognize that it is a special kind of collection, limited to zero or one elements. We can “comprehend” it too:

val dogBreeds = List(Some("Doberman"), None, Some("Yorkshire Terrier"), 
                    Some("Dachshund"), None, Some("Scottish Terrier"), 
                    None, Some("Great Dane"), Some("Portuguese Water Dog"))

println("first pass:")
for {
    breedOption <- dogBreeds
    breed <- breedOption  // Get text from Option.
    upcasedBreed = breed.toUpperCase()
} println(upcasedBreed)

println("second pass:")
for {
    Some(breed) <- dogBreeds
    upcasedBreed = breed.toUpperCase()
} println(upcasedBreed)

Imagine that we called some services to return various breed names. The services returned Options, because some of the services couldn’t return anything, so they returned None.

In the first expression of the first for comprehension, each element extracted is an Option this time. The next line uses the arrow to extract the value in the option.
The second for comprehension makes this even cleaner, using pattern matching. The expression Some(breed) <- dogBreeds only succeeds when the breedOption is a Some and it extracts the breed, all in one step.

Note:
Doesn’t None throw an exception if you try to extract an object from it? Yes, but the comprehension effectively checks for this case and skips the Nones.


Q: When do you use the left arrow (<-) versus the equals sign (=)?

A: You use the arrow when you’re iterating through a collection or other “container,” like an Option, and extracting values. You use the equals sign when you’re assigning a value that doesn’t involve iteration.

Note
1. A limitation is that the first expression in a for comprehension has to be an extraction/iteration using the arrow.
2. Scala for comprehensions do not offer a break or continue feature. Other features make them unnecessary.


Ref

《Programming Scala》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值