本文主要是介绍Scala实战专栏 (三) ——— 控制结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
scala-basic 基础篇
@author 鲁伟林
Scala基础知识介绍,主要包括《Scala编程实战》的基础章节GitHub地址: https://github.com/thinkingfioa/scala-in-action
本人博客地址: http://blog.csdn.net/thinking_fioa/article/details/78265745
3. 控制结构
Scala语言和Java语言在控制结构部分很像,但是又存在有趣的差别。 第3章项目源码阅读
3.1 for和foreach循环
循环语句主要用于处理三个问题: 1. 遍历一个集合中的所有元素; 2. 对集合中的每个元素进行某个操作; 3. 利用现有的集合创建新的集合
3.1.1 for循环常用的遍历
个人比较推荐如下for循环语法遍历集合
def forF(array : Array[String]): Unit = {for(entry <- array) {println(entry.toUpperCase())}}
3.1.2 从for循环中返回值
使用for/ield组合,输入一个集合,返回一个新的集合。在for循环添加yield实际上将每次循环的结果放入一个临时存放区。等循环结束后,以集合的形式返回。
def forYield(array : Array[String]) : Array[String] = {for(entry <- array) yield {entry.toUpperCase()}
}
3.1.3 for循环计数器
访问循环内的计数器,即通过一个计数器访问数组元素,使用array.indices
def forCount(array : Array[String]): Unit = {for(i <- array.indices) {println(s"$i is ${array(i)}")}
}
3.1.4 遍历一个Map
遍历Map中的键值对,下面的Map循环方法最简洁和可读
def forMap(namesMap : Map[String, Int]) : Unit = {for((k,v) <- namesMap) {println(s"key is $k, value is $v")}
}
3.1.5 另一种遍历集合方式
使用foreach, map, flatmap, collect, reduce等方法
- array.foreach(println) ----- 遍历array数组,可以使用自定义方法替换println方法
- array.foreach( e => println(e.toUpperCase)) ----- 使用匿名函数的语法
- array.foreach{ e => | val s = e.toUpperCase | println(s)|} ----- 实现多行函数
3.1.6 for循环式是如何被解释的
提供简化版的规则,帮助理解for循环执行过程
- 遍历集合的一个简单的for循环被解释为foreach方法调用
- 带有卫语句的for循环(3.3节)被解释为一个foreach调用后在集合上调用withFilter方法的序列
- 带有yield表达式的for循环被解释为集合上调用map方法
- 带有yield表达式和卫语句被解释为在集合上调用withFilter方法,紧接着一个map方法
3.2 在for循环中使用多个计数器
创建有多个计数器的循环,如遍历多维数组的情况。推荐使用大括号的代码风格,如下:
代码
def forMoreCount() : Unit = {for {i <- 1 to 3j <- 1 to 5k <- 1 to 10} {println("next: ")println(s"i : $i, j : $j, k : $k")}
}
3.3 在for循环中嵌入if语句(卫语句)
for循环中添加一个或者多个条件语句,典型的应用场景就是将一个元素从集合中过滤掉。 推荐使用大括号编码风格
代码
def forIf() : Unit = {for {i <- 1 to 10if i> 3if i<= 8if i % 2 == 0} println(i)
}
3.4 创建for表达式( for/yield组合 )
对一个已有的集合中的每个元素应用某个算法,从而生成新的集合。在for循环中使用yield语句的方式通常被叫作for推导
代码
def forYieldMoreLine(array : Array[String]) : Array[Int] = {for( e <- array) yield {val eUpper = e.toUpperCase()eUpper.length}
}
理解for/yield表达式
- 开始运行时,for/yield循环立刻创建一个新的空集合(Bucket),类型与输入的集合相同
- for循环每次遍历,都会在输入集合中的每个元素基础上创建新的元素,加入到Bucket中
- 循环结束后,Bucket中的所有内容都被返回
3.5 实现break和continue
遗憾的是Scala没有break或者continue关键字,但是scala.util.control.Breaks提供了类似的功能。相对于Java来说,Scala的break和continue较为复杂化。个人不喜欢这种风格
代码
import util.control.Breaks._object Ctrl3P5 {def forBreak(array : Array[Int]) : Unit = {breakable {for(i <- array) {if(i== 2) {break()} else {print(i+", ")}}}}def forContinue(array : Array[Int]) : Unit = {for(i <- array) {breakable {if(i== 2) {break()} else {print(i +", ")}}}}
}
3.6 像三元运算符一样使用if
Java提供条件运算符 ? : 称为三元运算符,但是Scala没有提供。在scala中只能使用if/else语句。eg x >=0 ? "yes": "no" 等价于 if(x>=0) "yes" else "no"
3.7 像swtich语句一样使用匹配表达式
Java中基于整数的switch语句,Scala也支持使用@switch注解来满足switch语句,同时@switch注解性能会更优越
代码
def switchTypo(i : Int) : String = {(i : @switch) match {case 1 => "One"case 2 => "Two"case _ => "Other"}
}
匹配表达式不局限于整数,它是非常灵活的,如下类型的匹配也是支持的
代码
def switchType(x : Any) : String = {(x : @switch) match {case s : String => "One"case i : Int => "Two"case _ => "Other"}
}
3.7.1 处理缺省情况
处理缺省情况的两种情况:
- 不关心缺省匹配的值,使用通配符去捕获 ----- case _ => println("default")
- 关系缺省匹配的值,指定一个变量,然后在表达式右侧使用该变量 ----- case default => println(default)
- 如果不处理缺省情况,可能会产生MatchError错误。所以建议要处理default case
3.8 一条case语句匹配多个条件
多个匹配条件需要执行相同的业务逻辑时,使用一条case语句匹配多个条件
代码
def moreCase(x : Int) : Unit = {(x : @switch) match {case 1 | 3 | 5 | 7 | 9 => println("odd")case 2 | 4 | 6 | 8 | 10 => println("even")}
}
3.9 将匹配表达式的结果赋值给变量
将一个匹配表达式返回值赋值给一个变量,或将匹配表达式作为方法的主体
def isTrue(a : Any) = a match{case 0 | "" => falsecase _ => true
}
3.12 在匹配表达式中使用Case类
在一个匹配表达式中匹配不同的case类(或者case对象)。如下面的代码,Dog和Cat case类以及Woodpecker case对象都是Animal trait的子类型
代码
trait Animalcase class Dog(name : String) extends Animalcase class Cat(name : String) extends Animalcase object Woodpecker extends Animalobject Ctrl3P11 {def main(args: Array[String]): Unit = {println(determineType(Dog("ppp")))println(determineType(Cat("fioa")))println(determineType(Woodpecker))}def determineType(x : Animal) : String = x match {case Dog(moniker) => "Got a Dog, name = "+monikercase _ : Cat => "Got a Cat"case Woodpecker => "That was a Wood"case _ => "default"}}
3.13 给Case语句添加if表达式(卫语句)
给匹配的表达式内的case语句添加合适的逻辑,帮助增强case语句的约束条件
object Ctrl3P13 {def main(args: Array[String]): Unit = {caseIfNum(1)caseIfNum(2)}def caseIfNum(x : Int) : Unit = {(x : @switch) match {case m if m==1 => println("one, a lonely number")case n if n==2 || n==3 => println(n)case _ => println("default")}}
}
3.14 使用匹配表达式替换isInstanceOf
判断对象是否匹配一个类型,可以通过使用isInstanceOf来判断,eg: if(x isInstanceOf[Class]) 。但当需求负责情况写,写一个代码块去匹配一种类型或者多个不同的类型的可读性更好。
代码
trait SentientBeing
trait Animal2 extends SentientBeing
case class Pig(name : String) extends Animal2
case class Person(name:String, age : Int) extends SentientBeingobject Ctrl3P14 {def main(args: Array[String]): Unit = {casePrintInfo(Person("luweilin", 24))casePrintInfo(Pig("ppp"))if(Pig("ppp").isInstanceOf[SentientBeing]) {println("true")}}def casePrintInfo(x : SentientBeing) : Unit = x match {case Person(name, age) => println(s"$name is $name, age is $age")case Pig(name) => println(s"pig name is $name")case _ => println("default")}
}
3.15 在匹配的表达式中使用List
List数据结构和其他的集合数据结构略有不同。列表由单元开始,Nil元素结尾。如果下递归打印内容
object Ctrl3P15 {def main(args: Array[String]): Unit = {val x = List(1,2,3,4)println(caseList(x))}def caseList(x : List[Int]) : String = x match {case s :: rest => s +", " + caseList(rest)case Nil => ""}
}
3.16 用try/catch匹配一个或多个异常
在try/catch块捕捉一个或者更多的异常
def moreException(fileName : String) : Unit = {try {// read config File} catch {case e : FileNotFoundException => println("Colud find that file.")case e : IOException => println("IOException trying to read that file")}
}
注意: Scala中没有受检异常,因此不需要指定抛出异常的方法。如果需要声明方法抛出的异常,或者需要和Java交互,在定义方法时添加@throws注解
@throws(classOf[NumberFormatException])
def throwException(fileName : String) : Unit = {try {// read config File} catch {case e : NumberFormatException => throw e}
}
3.17 在try/catch/finally块中使用变量前定义变量问题
在try代码中使用一个变量,并在finally代码块中访问该对象,如调用对象的close方法。一般情况下,在try/catch块前声明字段为Option,然后在try子句中创建一个Some对象,finally中执行关闭。在Scala中建议不要使用null
代码:
def tryCatchFinally(fileName : String) : Unit = {var in = None : Option[FileInputStream]try {// open file Name} catch {case cause: IOException => cause.printStackTrace()} finally {if(in.isDefined) {in.get.close()}}
}
3.18 创建自定义控制结构
Scala语言的创造者有意决定通过Scala类库去实现功能而不是去创建一些关键字。典型的例子就是: break和continue关键字。开发者可以自定义控制结构,创建可用的DSL去给他人所用
3.18.1 创建一个类似于while循环控制结构
object Ctrl3P18 {def main(args: Array[String]): Unit = {var i =0whilst(i<5) {println(s"index: $i")i += 1}}@tailrecdef whilst(testCondition : => Boolean) (codeBlock : => Unit) {if(testCondition) {codeBlockwhilst(testCondition)(codeBlock)}}
}
解释:
自定义函数名:whilst,接受两个参数列表,第一个是参数列表测试条件,一个表示用户想要运行的代码块
这篇关于Scala实战专栏 (三) ——— 控制结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!