文档章节

内建控制结构之for表达式

柳哥
 柳哥
发布于 2014/06/07 12:33
字数 1569
阅读 71
收藏 1

Scala的for表达式是枚举操作的“瑞士军刀”,它可以让你用不同的方式把若干简单的成分组合起来以表达各种各样的枚举。


枚举集合类
For能做的最简单的事情就是把集合中所有元素都枚举一遍。如例:

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        val fileHere = (new java.io.File(".")).listFiles
        for(file <- fileHere) println(file)
    }
}

通过使用被称为发生器的语法“file <- filesHere”,我们遍历了filesHere的元素。每一次枚举,名为file的新的val就被元素值初始化。编译器能够推断出file的类型是File,因为fileHere是Array[File]。对于每一次枚举,for表达式的函数体println(file),将被执行一次。由于File的toString方法生成文件或目录的名称,因此当前目录的所有文件和目录的名称都会被打印出来。
For表达式语法对任何种类的集合类都有效,而不只是数组。如例,你可以使用类似“1 to 5”这样的语法很方便地创建Range(这个后面再讲解),然后用for做枚举。

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        for(i <- 1 to 9) println("Iteration " + i)
    }
}

如果不想包括被枚举的Range上边界,还可以用until替代to,如例:

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        for(i <- 1 until 9) println("Iteration " + i)     //注意这里
    }
}


过滤
有时候你并不想枚举集合的全部元素,而只是想过滤出某个子集。这可以通过在for表达式的括号中添加过滤器(if子句)实现。如例:

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        for(i <- 1 until 9 if i % 2 == 0) println("Iteration " + i)
    }
}

或者也可以采用如下写法:

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        for(i <- 1 until 9)
            if(i % 2 == 0) println("Iteration " + i)
    }
}

这段代码对于指令式背景的程序员来说看上去更熟悉一些。然而指令式的格式只是可选的实现方法之一。For表达式之所以被称为“表达式”是因为它能产生有意义的值,其类型取决于for表达式<-子句的集合。需要的话,你可以包含更多的过滤器。只要不断添加if子句即可。如例:

package scalaTest
object Test4 {
    def main(args:Array[String]){
        for(
            i <- 1 until 9
            if i % 2 == 0;    //注意这里要分号
            if i % 4 == 0
        ) println("Iteration " + i)
    }
}

注意:如果在发生器中加入超过一个过滤器,if子句必须用分号分隔注:在scala2.10.7版本下好像不用分号了!!!)。


嵌套枚举
如果加入多个 <-子句,你就得到了嵌套的“循环”。如下例:

package scalaTest
object Test4 {
    def main(args:Array[String]){
        val arr = Array(Array(1,2,3,4,5),Array(11,12,13,14,15))
        for(
            ar <- arr
            if ar(0) > 10;    //注意这里要加分号
            a <- ar
            if a % 2 == 0 
        )println("Iteration " + a)
    }
}

注意嵌套枚举之间也必须用分号分隔。如果愿意的话,你可以使用花括号代替小括号包裹发生器和过滤器你用花括号的好处是可以省略使用小括号时必须加的分号(当然不去掉分号也是可以的);如例:

package scalaTest
object Test4 {
    def main(args:Array[String]){
        val arr = Array(Array(1,2,3,4,5),Array(11,12,13,14,15))
        for{        //注意这里,是大括号哦
            ar <- arr if ar(0) > 10
            a <- ar if a % 2 == 0
        }println("Iteration " + a)
    }
}


流间变量绑定

package scalaTest
object Test4 {
    def main(args:Array[String]){
        val arr = Array(Array("  a","b"," c "),Array("D","  E","F   "))
        for{
            ar <- arr if ar(0).trim == "a"
            a <- ar if a.trim == "c"
        }println(a.trim)
    }
}

请注意前面的代码段中重复出现了表达式a.trim,这是个不可忽略的计算,因此你或许希望只算一遍。这可以通过用等号(=)把结果绑定到新变量实现。绑定的变量被当作val引入和使用,不过不带关键字val,如例:

package scalaTest
object Test4{
    def main(args:Array[String]){
        val arr = Array(Array("a","b  ","  c  "),Array("D","  E","F   "))
        for{
            ar <- arr if ar(0).trim == "a"
            a <- ar            //注意,这里要么换行,要么加分号
            k = a.trim if k == "c"
        }println(k)
    }
}

不换行,加分号的例子:

package scalaTest
object Test4 {
    def main(args:Array[String]) {
        val arr = Array(Array(" a","b "," c "),Array("D","  E","F  "))
        for{
            ar <- arr if ar(0).trim == "a"
            a <- ar;k = a.trim if k == "c"    //这里加了分号
        }println(k)
    }
}

代码中,名为k的变量被从半路引入for表达式,并被初始化为a.trim的结果值。于是之后的for表达式在两个地方使用了新的变量,一次在if中,另一次在println中。


制造新集合
到现在为止所有的例子都只是对枚举值进行操作然后就释放,除此之外,你还可以创建一个值去记住每一次的迭代只要在for表达式之后加上关键字yield。如例:

package scalaTest
object Test4 {
    def main(args:Array[String]){
        val arr = Array(Array(" a","b "," c "),Array("D","  E","F  "))
        //注意这里
        var arr2 = for{
            ar <- arr if ar(0).trim == "a"
            a <- ar;k = a.trim if k == "c" || k == "b"
        }yield k
        for(s <- arr2) println("子集合元素: " + s)
    }
}

又例:

package scalaTest
object Test4{
    def main(args:Array[String]){
        val arr = Array(Array(" a","b "," c "),Array("D","  E","F  "))
        def fuOne(arr:Array[Array[String]]) = for{
            ar <- arr if ar(0).trim == "a"
            a <- ar;k = a.trim if k== "c" || k == "b"
        }yield k
        for(s <- funOne(arr)) println("子集合元素: " + s)
    }
}

For表达式在每次执行的时候都会产生一个新值,本例中是k。当for表达式完成的时候,结果将是包含了所有产生值的集合对象。对象的类型基于枚举子句处理的集合类型(上例中就是Array[String],这里是一维的)。
另外,请注意放置yield关键字的地方。对于for-yield表达式的语法是这样的 :for {子句} yield {循环体},如例:

package scalaTest
object Test4 {
    def main(args:Array[String]){
        val arr = Array(Array(" a","b "," c "),Array("D","  E","F  "))
        def funOne(arr:Array[Array[String]]) = for{
            ar <- arr if ar(0).trim == "a"
            a <- ar;k = a.trim if k == "c" || k == "b"
        }yield{
            println("~~~~~" + k)
            k
        }
    }
}

yield在整个循环体之后。即使循环体是被花括号包围的代码块,也一定要把yield放在左花括号之后
截止目前,你已经看过了scalafor表达式的所有主要特征,不过这一段过得实在是快了一些,我们后面会再详细介绍。

© 著作权归作者所有

共有 人打赏支持
柳哥
粉丝 203
博文 405
码字总数 347782
作品 0
杭州
技术主管
freemarker语法介绍及其入门

FreeMarker标签使用 一、FreeMarker模板文件主要有4个部分组成 1、文本,直接输出的部分 2、注释,即<#--...-->格式不会输出 3、插值(Interpolation):即${..}或者#{..}格式的部分,将使用数...

wersdffg
2014/09/30
0
0
freemarker总结

Freemarker 使用总结 FreeMarker模板文件主要由如下4个部分组成: 文本:直接输出部分 注释:<!-- …-->格式部分,不输出 插值:即${}或者#{}部分,使用数据模型中的部分替代输出. FTL指令:freema...

忘川-hsm
2016/11/01
7
0
FreeMarker标签介绍及各种数据类型处理

FreeMarker标签使用 一、FreeMarker模板文件主要有4个部分组成 1、文本,直接输出的部分 2、注释,即<#--...-->格式不会输出 3、插值(Interpolation):即${..}或者#{..}格式的部分,将使用数...

驛路梨花醉美
2016/11/29
17
0
看书 Python 源码分析笔记 (五)

第9章 Python 虚拟机中的一般表达式 这里一般表达式指对象创建语句, 打印语句等. if, while 等归为控制流语句于下一章. 简单内建对象的创建 示例 python 代码: i = 1 // int objects = "Pyt...

刘军兴
2015/12/21
78
0
FreeMarker标签介绍

FreeMarker标签使用 一、FreeMarker模板文件主要有4个部分组成 1、文本,直接输出的部分 2、注释,即<#--...-->格式不会输出 3、插值(Interpolation):即${..}或者#{..}格式的部分,将使用数...

机器学习
2013/04/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java GC机制详解

垃圾收集 Garbage Collection 通常被称为“GC”,本文详细讲述Java垃圾回收机制。 导读: 1、什么是GC 2、GC常用算法 3、垃圾收集器 4、finalize()方法详解 5、总结--根据GC原理来优化代码 ...

小刀爱编程
23分钟前
1
0
ORACEL学习--理解over()函数

二、理解over()函数 1.1、两个order by的执行时机 分析函数是在整个sql查询结束后(sql语句中的order by的执行比较特殊)再进行的操作, 也就是说sql语句中的order by也会影响分析函数的执行结果...

spinachgit
25分钟前
1
0
抽象语法树

import asttree = ast.parse('def hello_word(): print("hello world!")')def hell_word(): print(1)print(ast.dump(tree)) 语法树 可以基于这个实现另外一种编程语言...

colin_86
25分钟前
2
0
Akka查询设备组《fourteen》译

加入以下依赖到项目中: 介绍: 到目前为止,我们看到的会话模式很简单,因为它们要求Actor保持很少或没有状态。 特别: 设备actor返回一个读数,不需要更改状态。 记录温度,更新单个字段。...

woshixin
32分钟前
1
0
wait、notify、notifyAll 的用法

wait()、notify()、notifyAll()是三个定义在Object类里的方法,用来控制线程的状态。这三个方法最终调用的都是jvm的native方法, 随着jvm运行平台的不同可能有些许差异。 wait(): 使持有该对...

noob_fly
34分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部