for循环与if语句是各个编程语言中最常用的控制结构语句。在Scala中,for循环的特性被成为for推导式或者for表达式。
1. for循环的普通用法
我们现在以一个基本的for表达式开始,逐渐熟悉for推导式的各种用法:
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane", "ortuguese Water Dog")
for (breed <- dogBreeds)
println(breed)
Scala中for表达式写法与Java等其他语言有实质的区别,在Scala中引入生成器表达式(breed <- dogBreeds)的概念.生成器表达式会基于集合生成单独的数值,然后进行遍历。而Java的写法却需要定义一个循环变量或者使用JDK1.5以后提供的forEach写法,如:
List<String> dogBreeds = new ArrayList<String>();
dogBreeds.add("Doberman");
dogBreeds.add("Yorkshire Terrier");
dogBreeds.add("Dachshund");
dogBreeds.add("Scottish Terrier");
dogBreeds.add("Great Dane");
dogBreeds.add("ortuguese Water Dog");
//普通for循环
for(int i = 0 ; i < dogBreeds.size() ; i++){
System.out.println(dogBreeds.get(i));
}
//foreach循环方式
for(String dog : dogBreeds){
System.out.println(dog);
}
从上述代码中我们可以看出Scala代码的简洁,同样的功能,Scala的代码量将减小60+%。对于这一点,后续的代码也会有明显的例证。
2. for保护式,过滤数据
在实际开发中,我们经常会在for循环中增加一些过滤条件以方便处理数据或者缩小处理范围,如上例,我们可能只是关注包含“Terrier”的Dog,这样,我们的代码将改为:
List<String> dogBreeds = new ArrayList<String>();
dogBreeds.add("Doberman");
dogBreeds.add("Yorkshire Terrier");
dogBreeds.add("Dachshund");
dogBreeds.add("Scottish Terrier");
dogBreeds.add("Great Dane");
dogBreeds.add("ortuguese Water Dog");
//普通for循环
for(int i = 0 ; i < dogBreeds.size() ; i++){
String dog = dogBreeds.get(i);
if(dog.contains("Terrier"){
System.out.println(dogBreeds.get(i));
}
}
//foreach循环方式
for(String dog : dogBreeds){
if(dog.contains("Terrier"){
System.out.println(dogBreeds.get(i));
}
}
在Java中,我们是在for循环体中写if表达式,用于过滤并处理数据。但是在Scala中,保护式可以更简单的完成类似功能。保护式主要是用于筛选出我们希望保留的元素
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
for (breed <- dogBreeds if breed.contains("Terrier")) println(breed)
上述代码虽然与Java实现相同功能,但是Scala更加简洁,而且代码可读性更强。而且我们在开发中要重点注意的是:Scala保护式不是写在For循环体中,而是直接写在For表达式中。 Scala也支持在for循环中添加多个表达式。例如,我们可能不需要处理“Scottish Terrier”,则可以写为:
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
for (breed <- dogBreeds if breed.contains("Terrier") if !breed.startsWith("Yorkshire")) println(breed)
for (breed <- dogBreeds
if breed.contains("Terrier") && !breed.startsWith("Yorkshire")
) println(breed)
3. Scala的Yielding
前边所有实例代码都是在For循环中直接处理数据,我们使用for循环还有一个作用就是缩小处理数据的范围或者获取一个满足条件的数据集。在Java中,如果实现这个功能,我们可能会对数据集循环,并且新建一个List用于存放满足条件的数据,最后将新建的LIst对象反回给调用者,这里就不用Java代码来表示。在Scala中,我们使用yield关键字就可以在for表达式中生成新的集合。
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
val filteredBreeds = for {breed <- dogBreeds
if breed.contains("Terrier") && !breed.startsWith("Yorkshire")
} yield breed
每次执行for循环表达式时,过滤后的结果将生成bread值。而yield将这些结果累积起来,并且将这些集合赋值给fileteredBreeds对象。代码执行结果时值包含一个元素的List元素,唯一的元素值是“Scottish Terrier”。
需要注意事项
- 在执行for循环时,for表达式即可以使用小括号(圆括号),也可以使用花括号。其执行结果是一样的。
- for-yield表达式中,Scala会根据源的类型进行类型推导,生成的新表达式与原表达式类型相同。由于dogBreeds类型为List[String],则僧成的filteredBreeds的类型也为List[String]。
1. 扩展作用域与值定义
扩展作用域:Scala的for推导式中的最初部分定义值,并可以在后边表达式中使用该值。如下所示:
val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
for {
breed <- dogBreeds
upcasedBreed = breed.toUpperCase()
} println(upcasedBreed)
在上述代码中,upcasedBreed的值是不可以变的,但是这样的语法是不需要使用val关键字进行限定。