Scala的内建控制结构
Scala中的内建控制机构仅有if、while、for、try、match和函数调用。虽然Scala的基础控制结构少,但也足以支持指令式语言里所有的实质内容。因为它们都能产生值,有助于缩短代码。
程序员可以通过使用返回值的控制结构简化代码,避免创建临时变量来保存控制结构中的计算结果。
1 If表达式
1.1.常规式
var filename="default"
if(!args.isEmpty)
filename=args(0)
1.2.scala里根据条件做初始化的例子
val filename=
if(!args.isEmpty) args(0)
else "default.txt"
这样写有两个好处:
一是使用val体现了函数式风格,并具有java的final变量类似的效果。它告诉读者,代码变量将不再改变,从而节省了他们审查变量作用域的所有代码和检查它是否改变的工作。
二是更好地支持等效推论。在表达式没有副作用的前提下,引入的变量等效于计算它的表达式。无论何时都可以用表达式替换变量名。
尽可能使用val,它能让你的代码既容易阅读又容易重构。
2.While循环
2.1常规式
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
}
例如Do-While循环
var line =""
do {
line=readLine()
println("Read: "+line)
} while(line!="")
while和do-while结构之所以称之为“循环”,而不是表达式,因为他们不能产生有意义的结果,结果类型只能是Unit类型,是表明存在且唯一存在类型为Unit的值,写成()。()的存在是scala的Unit与Java的void不同的地方,例如
def greet() {println("hi")}
greet()==()
以上代码将返回true。因为greet返回unit值()。所有greet的结果和unit值()相等,返回true。
另外需要注意的是,赋值等式本身也是unit值
例如var line=""
while((line=readLine())!="") //不起作用
println("Read: "+line)因为赋值语句line=readLIne()的值将永远返回()而不是”“
建议你在代码中更为审慎地使用while循环。如果对while或do循环没有非用不可的理由,请尝试别的方式实现同样的功能。
3.For表达式
scala的For表达式是枚举操作的瑞士军刀。
3.1枚举集合类
val filesHere=(new java.io.File(".")).listFiles
for(file<- filesHere)
println(file)
通过被称为发生器语法“file<-filesHere”,遍历了filesHere数组的元素。
for表达式语法对任何种类的集合类都有效,而不只是数组。例如Range
for(i<-1 to 4)
println("Iteration "+i)
以下这种方式遍历数组不常用:
for(i<-0 to filesHere.length-1)
println(filesHere(i))
不常用的原因是由于集合本身可以直接被枚举,并且不会出现溢出。
3.2 过滤
又是不想枚举处全部元素,只想过滤出某个子集。这可以通过for表达式的括号中添加过滤器(filter),即if子句。例如过滤以.scala为结尾的文件名:
val filesHere = (new java.io.File(".")).listFiles
for(file<-filesHere if file.getName.endsWith(".scala"))
println(file)
也可以加入更多的过滤器,只要不断添加if子句即可。如果发生器中超过一个过滤器,if子句必须用分号分隔。
for(
file<-fileHere
if file.isFile;
if file.getName.endsWith(".scala")
) println(file)
3.3嵌套枚举
如果加入多个<-子句,就可以嵌套循环。例如:
def fileLines(file:java.io.File)=
scala.io.Source.fromFile(file).getLines.toList def grep(pattern:String)=
for(
file<-fileHere
if file.getName.endsWith(".scala")
line<-fileLines(file)
if line.trim.mathches(pattern)
) println(file+": "+line.trim) grep(".*gcd.*")
3.4 流间变量绑定
在前面的代码中重复出现了表达式line.trim。如果想要只计算一遍,可以通过等号=把结果绑定到新的变量。绑定变量被当做val引入和使用,但是不带关键字val。
def grep(pattern:String)=
for(
file<-fileHere
if file.getName.endsWith(".scala")
line<-fileLines(file)
trimmed=line.trim
if trimmed.mathches(pattern)
) println(file+": "+trimmed) grep(".*gcd.*")
3.5 制造新的集合
到现在为止所有例子只是对枚举值进行操作然后释放,除此以为,还可以创建一个值去记住每一次的迭代,只要在for表达式之前加上关键字yield。比如:
def scalaFiels=
for{
file<-filesHere
if file.getName.endsWith(".scala")
} yield file
for表达式在每次执行的时候都会产生一个新值,本例中是file。当for表达式完成的时候,结果将是包含了产生值的集合对象。对象的类型基于枚举子句处理的集合类型。本例中的结果为Array[File],因为filesHere是数组并且产生的表达式类型是File。
另外注意yield一定放在左括号之前,而不是代码块的最后一个表达式之前。
for {子句} yield {循环体}
val forLineLengths=
for {
file<- filesHere
if file.getName.endsWith(".scala")
line<-fileLines(file)
trimmed = line.trim
if trimmed.matches(".*for.*")
} yield trimmed.length
4使用try表达式处理异常
Scala中方法处理能返回值以外,还可以通过抛出异常中止执行。方法的调用者要么可以捕获并处理这个异常,或者也可以简单的终止掉,并把异常上升到调用者的调用者处。
4.1抛出异常
throw也是有结果类型的表达式,例如:
val half=
if (n%2==0)
n/2
else
throw new RuntimeException("n must be even")
异常抛出的类型是Nothing。
像这样的例子经常使用。if的一个分支计算值,另一个爆出异常并得出Nothing。
4.2捕获异常
在scala中捕获异常时,在catch子句中经常使用case模式匹配,这是scala的特色。模式匹配是一种很强大的特征。
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try{
val f= new FileReader("inpit.txt")
} catch{
case ex:FileNotFoundException=>//处理丢失的文件
case ex:IOException=> //处理其他的IO错误
Scala里不需要捕获检查异常,或者把他们生命在throws子句中。
4.3 finally子句
如果要让某些代码无论如何都要执行的话,可以放在finall子句中。例如:
import java.io.FileReader val file=new FileReader("input.txt")
try{
//使用文件
}finally {
file.close() //确保关闭文件
}
在Scala中还可以使用另一种被称为出借模式(loan pattern)的技巧更简洁地达到同样的目的。
def withPrintWriter(file:File,op:PrintWriter=>Unit) {
val writer= new PrintWriter(file)
try {
op(writer)
} finally {
writer.close()
}
}
上面的代码中,由withPrintWriter而并非用户代码,确认文件在结尾被关闭。因为不可能忘记关闭文件。因为控制抽象函数,打开了资源并借贷给函数。当用户函数完成时,它发出信号说明它不再需要借的资源,于是资源被关闭在finally中,以确信其确实被关闭。
4.4生成值
try-catch-finally也产生值,但是finally子句应当做关闭文件之类的清理工作,他们不应该修改主函数体或catch子句中计算的值。
scala与java的try-finally最大的不同是,在java中finally子句不产生值。
def f():Int=try{return 1} finally {return 2}
def g():Int=try{1} finally{2}
调用f()返回2,调用g()返回1。
5.匹配表达式
scala中的match类似于java中的swith,但是他可以在提供多个备选项中做出选择。默认情况下用_说明。例如:
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?")
与Java相比,Scala的匹配表达式还有一些重要差别。
(1)任何类型的常量,或者其他东西都可以成为case,而不只是java中的整数类型和枚举常量。
(2)每个备选项的最后没有break,因为break是隐含的。
(3)match也能产生值。例如:val firstArg = if(!args.isEmpty) args(0) else "" val firend= firstArg match{
case "salt"=> println("pepper")
case "chips"=> println("salsa")
case "eggs"=> println("bacon")
case _ =>println("huh?")
}
println (frined)
Scala的内建控制结构的更多相关文章
- Scala学习笔记——内建控制结构
Scala的内建控制结构包括:if.while.for.try.match和函数调用 1.if表达式 //常见的写法 var filename = "name" if (!args ...
- Scala 编程(四)内建控制结构
if 表达式 Scala 的 if 如同许多其它语言中的一样工作.它测试一个状态并据其是否为真,执行两个分支中的一个: var filename = "default.txt" i ...
- scala编程(七)——内建控制结构
几乎所有的 Scala 的控制结构都会产生某个值.这是函数式语言所采用的方式,程序被看成是计算值的活动,因此程序的控件也应当这么做.另外,指令式语言经常具有三元操作符(如 C,C++和 Java 的? ...
- Scala学习笔记(五):内建控制循环
前言 Scala中内建控制循环包括if.while.for.try.match和函数调用. if和while与java类似,不做介绍. for 基础用法 def main(args: Array[St ...
- scala-- 内建控制结构
内建控制结构 scala 内建的控制结构很少,只有 if while for try match 和函数调用 几种. 因为scala 从语法层面支持函数字面量.几乎所有的scala控制结构都会产生 ...
- BASH BUILTIN COMMANDS 内建命令
除非另外说明,这一章介绍的内建命令如果接受 - 引导的选项,那么它也接受 -- 作为参数,来指示选项的结束 : [arguments] 没有效果:这个命令除了扩展 arguments 并且作任何指定的 ...
- Bash shell的内建命令:type
type指令是用来观察指令时来自于外部指令还是内建在bash中的指令. type [-tpa] name 选项与参数: :不加任何选项与参数时,type会显示出name是外部指令还是bash内建指 ...
- Bash Shell内建命令和保留字
Bash Shell内建命令和保留字命令含义!保留字,逻辑非:不做任何事,只做参数展开.读取文件并在shell中执行它alias设置命令或命令行别名bg将作业置于后台运行bind将关键字序列与read ...
- Python内建的对象列表
Python内建的对象列表 刚写Python肯定会遇到这样的情况,想写些什么,但又不知从何写起... 在我看来问题在于我们不知道有什么东东可以拿来玩,这里列出Python的内建对象,稍微归类了一下,多 ...
随机推荐
- 洛谷 P4779 :【模板】单源最短路径(标准版)(Dijkstra+堆优化+链式前向星)
题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 100→60: Ag→Cu: 最终,他因此没能与理想 ...
- 使用w uptime vmstat top sar nload 等命令查看系统负载
1. w 和uptime,查看cpu的使用率: 2.vmstat 命令,查看更细的物理设备使用状况: 3.top 命令: top -c 可具体查看命令及路径: top -bn1 静太显示一条命令, ...
- net框架平台下RPC框架选型
net RPC框架选型 近期开始研究分布式架构,会涉及到一个最核心的组件:RPC(Remote Procedure Call Protocol).这个东西的稳定性与性能,直接决定了分布式架构系统的好坏 ...
- springboot+kotlin+springcloud+java+grade+maven混编?
springboot + maven + java vs springboot + gradle + kotlin 快速搭建:https://start.spring.io/ springclould ...
- 【二分图最大权完美匹配】【KM算法】【转】
[文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] ...
- 计算机网络-数据结构-MAC帧头-IP头-TCP头-UDP头
第0章 数据是如何进行一步步的封装的 第一章:mac帧头定义 帧头数据结构的定义: 一.MAC帧头定义 /*数据帧定义,头14个字节,尾4个字节*/ typedef struct _MAC_FRAME ...
- zeebe 为微服务架构的工作流引擎
zeebe 是灵活.轻量的基于微服务架构的工作流引擎 包含以下特性: 可视化的额工作流 审计日志以及历史 水平缩放 持久化&&容错 消息驱动 操作容易 语言无关 工作流基于标准bpmn ...
- PowerDesigner V16.5 安装及汉化
一.power designer是什么以及是干什么的? power designer是能进行数据库设计的强大的软件,是一款开发人员常用的数据库建模工具.分别从概念数据模型(Conceptual Dat ...
- 持续集成--Jenkins--2
安装sonar Scanner 打开http://www.sonarqube.org/官网 找到下面扫描器 通过这个扫描器可以分析代码分析 因此你也的安装这个扫描器 上传sonar-scanner-2 ...
- Nginx浏览目录配置及美化
https://segmentfault.com/a/1190000012606305 在项目中有一个功能需要在浏览器页面中浏览服务器的目录.服务器使用Nginx,而Nginx提供了相应的ngx_ht ...