文档章节

内建控制结构之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

没有更多内容

加载失败,请刷新页面

加载更多

下一页

八大包装类型的equals方法

先看其中一个源码 结论:八大包装类型的equals方法都是先判断类型是否相同,不相同则是false,相同则判断值是否相等 注意:包装类型不能直接用==来等值比较,否则编译报错,但是数值的基本类型...

xuklc
31分钟前
1
0
NoSQL , Memcached介绍

什么是NoSQL 非关系型数据库就是NoSQL,关系型数据库代表MySQL 对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很耗...

TaoXu
昨天
0
0
890. Find and Replace Pattern - LeetCode

Question 890. Find and Replace Pattern Solution 题目大意:从字符串数组中找到类型匹配的如xyy,xxx 思路: 举例:words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"abc ......

yysue
昨天
0
0
Linux | Redis

写在前面的话 常言道,不作笔记不读书。在下是深有体会啊,所以,跟我一起做下本节的笔记吧,或许多年以后,你一定会感谢今天的你。 安装 在官网的下载页 Redis Download 直接写了在Linux的安...

冯文议
昨天
1
0
NoSQL-memcached

NoSQL介绍 NoSQL叫非关系型数据库。而关系型数据库代表有MySQL。对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很...

ln97
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部