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

相关文章

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

Oracle Scheduler任务故障诊断方法实战指南

《OracleScheduler任务故障诊断方法实战指南》Oracle数据库作为企业级应用中最常用的关系型数据库管理系统之一,偶尔会遇到各种故障和问题,:本文主要介绍OracleSchedul... 目录前言一、故障场景:当定时任务突然“消失”二、基础环境诊断:搭建“全局视角”1. 数据库实例与PDB状态2

Git进行版本控制的实战指南

《Git进行版本控制的实战指南》Git是一种分布式版本控制系统,广泛应用于软件开发中,它可以记录和管理项目的历史修改,并支持多人协作开发,通过Git,开发者可以轻松地跟踪代码变更、合并分支、回退版本等... 目录一、Git核心概念解析二、环境搭建与配置1. 安装Git(Windows示例)2. 基础配置(必

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Maven中生命周期深度解析与实战指南

《Maven中生命周期深度解析与实战指南》这篇文章主要为大家详细介绍了Maven生命周期实战指南,包含核心概念、阶段详解、SpringBoot特化场景及企业级实践建议,希望对大家有一定的帮助... 目录一、Maven 生命周期哲学二、default生命周期核心阶段详解(高频使用)三、clean生命周期核心阶