Scala 编程(四)内建控制结构
if 表达式
Scala 的 if 如同许多其它语言中的一样工作。它测试一个状态并据其是否为真,执行两个分支中的一个:
- var filename = "default.txt"
- if (!args.isEmpty)
- filename = args(0)
由于 Scala 的 if 是能返回值的表达式,可以改成用 val 的更函数式的风格:
- val filename =
- if (!args.isEmpty) args(0)
- else "default.txt"
使用 val 而不是 var 的第二点好处是他能更好地支持等效推论:equational reasoning。在表达式没有副作用的前提下,引入的变量等效于计算它的表达式。因此,无论何时都可以用表达式替代变量名:
- println(if (!args.isEmpty) args(0) else "default.txt")
while 循环
Scala 的 while 循环表现的和在其它语言中一样。包括一个状态和循环体,只要状态为真,循环体就一遍遍被执行:
- def gcdLoop(x: Long, y: Long): Long = {
- var a = x
- var b = y
- while (a != 0) {
- val temp = a
- a = b % a
- b = temp
- }
- B
- }
Scala 也有 do-while 循环。除了把状态测试从前面移到后面之外,与 while 循环没有区别。
While 和 do-while 结构被称为“循环”,不是表达式,因为它们不产生有意义的结果,结果的类型是 Unit 。说明产生的值的类型为 Unit 。被称为 unit value ,写做 () 。 () 的存在是 Scala 的 Unit 不同于 Java 的 void 的地方:
- cala> def greet() { println("hi") }
- greet: ()Unit
- scala> greet() == ()
- hi
- res0: Boolean = true
由于方法体之前没有等号, greet 被定义为结果类型为 Unit 的过程。因此, greet 返回 unit 值 () 因此在比较 greet 的结果和 unit 值 () ,的相等性,产生true。
for 表达式
枚举集合类
用 for 做的最简单的事情就是把一个集合类的所有元素都枚举一遍:
- val filesHere = (new java.io.File(".")).listFiles
- for (file <- filesHere)
- println(file)
代码先创建指向当前目录 “.” 的文件,调用 listFiles 方法,返回 File 对象数组保存在 filesHere 变量中,通过发生器:generator的语法“file <- filesHere”遍历了 filesHere 的元素,每一次枚举 file 的新 val 就被元素值初始化并被打印出来。
for 表达式语法对任何种类的集合类都有效而不只是数组,可以使用类似于 “1 to 5” 这样的语法创建一个 Range ,然后用 for 枚举:
- scala> for (i <- 1 to 4)
- | println("lteration" + i)
- lteration1
- lteration2
- lteration3
- lteration4
过滤
有些时候不想枚举一个集合类的全部元素。而是想过滤出一个子集。可以通过把过滤器:filter:一个 if 子句加到 for 的括号里做到:
- val filesHere = (new java.io.File(".")).listFiles
- for (file <- filesHere if file.getName.endsWith(".scala"))
- println(file)
也可以这么写:
- for (file <- filesHere)
- if (file.getName.endsWith(".scala"))
- println(file)
如果愿意的话,可以包含更多的过滤器。只要不断加到子句里即可:
- for (
- file <- filesHere
- if file.isFile;
- if file.getName.endsWith(".scala")
- )println(file)
如果在发生器中加入超过一个过滤器, if 子句必须用分号分隔。
嵌套枚举
如果加入多个 <- 子句就得到嵌套的“循环”:
- def fileLines(file: java.io.File) =
- scala.io.Source.fromFile(file).getLines.toList
- def grep(pattern: String) =
- for {
- file <- filesHere
- if file.getName.endsWith(".scala")
- line <- fileLines(file)
- if line.trim.matches(pattern)
- } println(file + ": " + line.trim)
- grep(".*gcd.*")
代码展示的 for 表达式有两个嵌套循环,外层循环枚举 filesHere ,内层的枚举所有以 .scala 结尾的文件的 fileLines(file) 。可以使用大括号代替小括号环绕发生器和过滤器,这样的好处是可以省略一些使用小括号必须加的分号。
mid-stream (流间) 变量绑定
注意到前段代码中重复出现的表达式 line.trim ,这不是个可忽略的计算,如果想每次只算一遍,可以用等号 (=) 把结果绑定到新变量做到这点,绑定的变量被当做用 val 引入和使用,不过不用带关键字 val :
- def grep(pattern: String) =
- for {
- file <- filesHere
- if file.getName.endsWith(".scala")
- line <- fileLines(file)
- trimmed = line.trim
- if trimmed.matches(pattern)
- } println(file + ": " + trimmed)
- grep(".*gcd.*")
名为 trimmed 的变量被引入 for 表达式,并被初始化为 line.trim 的结果值。之后的 for 表达式就可以在两个地方使用这个新变量,一次在 if 中,一次在 println 中。
制造新集合
可以创建一个值去记住每一次的迭代,只要在 for 表达式之前加上关键字 yield :
- def scalaFiles =
- for {
- file <- filesHere
- if file.getName.endsWith(".scala")
- } yield file
for 表达式在每次执行的时候会制造一个值,当 for 表达式完成的时候,结果将是一个包含了所有产生的值的集合,结果集合的类型基于枚举子句处理的集合类型。 for-yield 表达式的语法:
- for {子句} yield {循环体}
yield 在整个循环体之前,即使循环体是一个被大括号包围的代码块,也一定把 yield 放在左括号之前而不是代码的最后一个表达式之前:
- for (file <-filesHere if file.getName.endsWith(".scala")) {
- yield file // 语法错误!
- }
使用 try 表达式处理异常
抛出异常
异常的抛出看上去与 Java 的一模一样。首先创建一个异常对象然后用 throw 关键字抛出:
- throw new IllegalArgumentException
Scala 里, throw 也是有结果类型的表达式,抛出异常的类型是 Nothing ,尽管 throw 不实际得出任何值,但还是可以把它当做表达式。
捕获异常
用来捕获异常的语法如下:
- import java.io.FileReader
- import java.io.FileNotFoundException
- import java.io.IOException
- try {
- val f = new FileReader("input.txt")
- // Use and close file
- } catch {
- case ex: FileNotFoundException => // Handle missing file
- case ex: IOException => // Handle other I/O error
- }
这个 try-catch 表达式的行为与其它语言中的异常处理一致。程序体被执行,如果抛出异常,每个 catch 子句依次被尝试。本例中,如果异常是 FileNotFoundException ,那么第一个子句将被执行。如果是 IOException 类型,第二个子句将被执行。如果都不是,那么try-catch将终结并把异常上升出去。
finally 子句
和其它大多数 Scala 控制结构一样, try-catch-finally 也产生值。 Scala 的行为与 Java 的差别仅源于 Java 的 try-finally 不产生值。 Java 里如果 finally 子句包含一个显式返回语句,或抛出一个异常,这个返回值或异常将“凌驾”于任何之前源于 try 代码块或某个它的 catch 子句产生的值或异常之上:
- def f(): Int = try { return 1 } finally { return 2 }
调用 f() 产生结果值 2 ,相反:
- def g(): Int = try { 1 } finally { 2 }
调用 g() 产生 1 。
match 表达式
Scala 的匹配表达式允许在许多可选项:alternative中做选择,就好象其它语言中的 switch 语句。 Match 表达式可以你使用任意的模式:pattern做选择:
- val firstArg = if (args.length > 0) args(0) else ""
- firstArg match {
- case "salt" => println("pepper")
- case "chips" => println("salsa")
- case "eggs" => println("bacon")
- case _ => println("huh?")
- }
match 缺省情况用下划线 (_) 说明,这是常用在 Scala 里作为占位符表示完全不清楚的值的通配符。
Scala 里的 case 匹配表达式可以使任何种类的常量,每个可选项最后没有 break ,但是 break 是隐含的。 match 表达式也能产生值:
- val firstArg = if (!args.isEmpty) args(0) else ""
- val friend =
- firstArg match {
- case "salt" => "pepper"
- case "chips" => "salsa"
- case "eggs" => "bacon"
- case _ => "huh?"
- }
- println(friend)
变量范围
Scala 程序里的变量定义有一个能够使用的范围:scope。大括号通常引入了一个新的范围,任何定义在大括号里的东西在括号之后就脱离了范围。
一旦变量被定义了就不能在同一范围内定义同样的名字,但是可以在内部范围内定义与外部范围内名称相同的变量,用大括号括起来即为内部范围。内部变量会遮蔽同名的外部变量。
Scala 编程(四)内建控制结构的更多相关文章
- Scala学习笔记——内建控制结构
Scala的内建控制结构包括:if.while.for.try.match和函数调用 1.if表达式 //常见的写法 var filename = "name" if (!args ...
- Scala的内建控制结构
Scala中的内建控制机构仅有if.while.for.try.match和函数调用.虽然Scala的基础控制结构少,但也足以支持指令式语言里所有的实质内容.因为它们都能产生值,有助于缩短代码. 程序 ...
- scala编程(七)——内建控制结构
几乎所有的 Scala 的控制结构都会产生某个值.这是函数式语言所采用的方式,程序被看成是计算值的活动,因此程序的控件也应当这么做.另外,指令式语言经常具有三元操作符(如 C,C++和 Java 的? ...
- Scala 基础(6)—— 控制结构
1. Scala 的内建控制结构 Scala 有几个内建的控制结构,包括: if 表达式 while 循环和 do-while 循环 for 表达式 try 表达式 match 表达式 Scala 的 ...
- scala-- 内建控制结构
内建控制结构 scala 内建的控制结构很少,只有 if while for try match 和函数调用 几种. 因为scala 从语法层面支持函数字面量.几乎所有的scala控制结构都会产生 ...
- Scala学习笔记(五):内建控制循环
前言 Scala中内建控制循环包括if.while.for.try.match和函数调用. if和while与java类似,不做介绍. for 基础用法 def main(args: Array[St ...
- CODING DevOps 系列第四课:DevOps 中的质量内建实践
什么是质量内建 随着时间的推移,我们项目的开发效率会逐渐降低,直到几年之后整个项目可能就无法维护,只能推倒重来.具体的表现首先就是随着时间推移,我们会发现整个需求列表里面能做的需求越来越少,因为每当我 ...
- javascript 对象初探 (四)--- 内建对象之旅之Array
我们不要去纠结神马是内建对象,神马是內建构造器.到后来你们便会发现其实她们都是对象. Array()是一个构建数组的內建构造器函数: var arr = new Array(); 与下面的是等效的: ...
- Unity3d 网络编程(一)(Unity3d内建网络Network介绍)
首先个人说说题外话,Unity3d使用的网络库核心是用C++实现的一款商业网络游戏引擎库. RakNet.所以对于移动设备来说,用Unity3d来写server是全然能够的,而且内建网络库的各项功能封 ...
随机推荐
- ios创建的sqlite数据库文件如何从ios模拟器中导出
为了验证数据库的结构,有的时候需要使用一些管理工具来直接查看sqlite数据库的内容,在windows下有sqlite3的专用工具下载,而在ios下也可以使用火狐浏览器的插件sqlitemanager ...
- Android Studio学习随笔-基本事件(点击)
最常见的点击事件有三种创建方法,在MainActivity.java的onCreate函数(在启动程序是优先运行的程序)中创建setOnClickListener(动态运行)(最常见) protect ...
- CDOJ 92 Journey(LCA&RMQ)
题目连接:http://acm.uestc.edu.cn/#/problem/show/92 题意:给定一棵树,最后给加一条边,给定Q次查询,每次查询加上最后一条边之后是否比不加这条边要近,如果近的话 ...
- 【分享】w32service table XPsp2
Ord Address fnAddr Symbols-------------------------------- [ 0] BF999280: BF93569A (win32k!Nt ...
- Overload和Override的区别?
Overload和Override的区别? Override是重写:方法名称.参数个数,类型,顺序,返回值类型都是必须和父类方法一致的.它的关系是父子关系Overload是重载:方法名称不变,其余的都 ...
- Struts2里如何取得request,session,application
第一种:取得MAP类型的request,session,application在java文件里写 package com.xjtu.st; import java.util.Map; import c ...
- jvm-初探
目录 1,Java体系结构 2.jvm执行引擎 3,ClassLoader的体系结构 4,java class文件 概述 其实,学java不算新手了,但是却感觉很多基本的知识,我们一开始也许是记住而不 ...
- tomcat启动项目内存溢出问题
catalina.bat文件的第二行加下面的即可: 注意最大内存设置,和系统的内存有关系 set JAVA_OPTS=%JAVA_OPTS% -Xms512m -Xmx1024m -XX:PermSi ...
- 【转】 iOS如何实现表格的折叠效果?
原文 : http://blog.csdn.net/youcanping2008/article/details/9202167 一.实现原理:就是在点击表格组头视图的时候,如果该表格视图的组展开了 ...
- Xcode7新特性
更新Xcode7之后报错: Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:], ...