Scala实战专栏 (三) ——— 控制结构

2024-03-31 06:48

本文主要是介绍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等方法

  1. array.foreach(println) ----- 遍历array数组,可以使用自定义方法替换println方法
  2. array.foreach( e => println(e.toUpperCase)) ----- 使用匿名函数的语法
  3. array.foreach{ e => | val s = e.toUpperCase | println(s)|} ----- 实现多行函数

3.1.6 for循环式是如何被解释的

提供简化版的规则,帮助理解for循环执行过程

  1. 遍历集合的一个简单的for循环被解释为foreach方法调用
  2. 带有卫语句的for循环(3.3节)被解释为一个foreach调用后在集合上调用withFilter方法的序列
  3. 带有yield表达式的for循环被解释为集合上调用map方法
  4. 带有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表达式

  1. 开始运行时,for/yield循环立刻创建一个新的空集合(Bucket),类型与输入的集合相同
  2. for循环每次遍历,都会在输入集合中的每个元素基础上创建新的元素,加入到Bucket中
  3. 循环结束后,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实战专栏 (三) ——— 控制结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/863690

相关文章

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例

《PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例》词嵌入解决NLP维度灾难,捕捉语义关系,PyTorch的nn.Embedding模块提供灵活实现,支持参数配置、预训练及变长... 目录一、词嵌入(Word Embedding)简介为什么需要词嵌入?二、PyTorch中的nn.Em

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

Spring Boot3.0新特性全面解析与应用实战

《SpringBoot3.0新特性全面解析与应用实战》SpringBoot3.0作为Spring生态系统的一个重要里程碑,带来了众多令人兴奋的新特性和改进,本文将深入解析SpringBoot3.0的... 目录核心变化概览Java版本要求提升迁移至Jakarta EE重要新特性详解1. Native Ima

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

SpringBoot集成MyBatis实现SQL拦截器的实战指南

《SpringBoot集成MyBatis实现SQL拦截器的实战指南》这篇文章主要为大家详细介绍了SpringBoot集成MyBatis实现SQL拦截器的相关知识,文中的示例代码讲解详细,有需要的小伙伴... 目录一、为什么需要SQL拦截器?二、MyBATis拦截器基础2.1 核心接口:Interceptor

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.