就是个控制结构,Scala能有什么新花样呢?

简介: 编程语言中最为基础的一个概念是控制结构,几乎任何代码都无时无刻不涉及到,其实也就无外乎3种:顺序、分支和循环。本文就来介绍Scala中控制结构,主要是分支和循环。

640.png

Scala中的控制结构实质上与其他编程语言并无太大差别,需要注意的是Scala中的控制结构大多具有返回值,而其他编程语言中的控制结构一般就仅仅是用于流程控制。本文主要目录如下:

  • 分支结构
  • if-else
  • match-case
  • 循环结构

  • for循环
  • while循环
  • do-while循环
  • break和continue


01 分支结构


分支结构应该编程中最为常用的控制结构了,典型的if-else也是最能代表程序员思维的了。这里首先插一个只有程序员才懂的段子:


女朋友对程序员说:“亲爱的,去超市买一个西瓜吧,如果他们还有鸡蛋,再买20个”,结果程员带了21个西瓜回家。女朋友愤怒地说:“为什么买21个西瓜回来”?程序员答:“因为他们确实有鸡蛋”。


这个冷笑话,其实质就是一个顺序结构+选择分支结构。那么在Scala中,分支结构当然也是用关键字if-else,更具体的说无外乎以下3种形式:


scala> val num = 2
val num: Int = 2
// 单分支
scala> if(num>1) print("greater")
greater
// 双分支
scala> if(num>1) print("greater") else print("less")
greater
// 多分支
scala> if(num>2) print("greater") else if(num==2) print("equal") else print("less")
equal


if-else是最常规的分支选择结构,Scala中也不例外。另外,除了以上三种形式外,当然还可以组织嵌套的if-else结构,但实质都是一样。形式虽然一样,但Scala中其实也有其特别之处:那就是Scala中的if-else其实应当理解成一个代码块,而在Scala中但凡是代码块,基本上都对应有返回值,所以无论是单分支、双分支还是多分支,其返回值就是相应分支的结果,虽然这个返回结果可能为Unit,例如上述print语句后其实就并未产生实际的返回值。同时需指出的是,在单分支中只有if单条语句,当条件不满足时实际上也是对应控制的返回结果。


正因为if-else都是有返回值的,所以Scala中并未设立像其他语言中那样的三元选择运算符,而是交由if-else完成这一功能。


除了if-else这种经典的分支结构外,编程语言中另一经典分支结构是switch-case结构,这在Scala中也是有所体现的,只不过未提供switch,而是支持功能更为强大的模式匹配:match-case,甚至有人将其称作是最能体现Scala特色和优势的特性之一。本文作为系列入门文章,仅就其实现最基础的分支结构做以说明。


scala> num match{  // match 关键字
         case x if(x<0) => print("<0")  // 代入条件判断
         case 0 => print("0")  // 直接以具体值判断
         case 1 => print("1")
         case _ => print("other") // 用_表示其他情况
       }
other


注:模式匹配在Scala中仍属于一个代码块,也是有返回值的。


在模式匹配中另外值得关注的一个细节是,在各匹配分支后,用映射符号"=>"连接条件和执行逻辑,这与Scala中函数的标志性符号是一致的,都表示映射的含义,一定程度上也暗示着模式匹配其实可理解为根据条件逻辑执行一个个的子函数。


02 循环结构


除了选择分支结构,程序中另外一个常用的循环。实话说,循环常常是在解决很多算法题目时最先想到的方案,虽然效率不高,但却非常简单粗暴和直观易懂。通常情况下,循环有3种结构:

  • for
  • while
  • do……while

Scala也不例外,而结合Scala的特性,这三种循环往往有着更为优雅的运用。


1)for循环。Scala中的for循环其实与Python中的for循环比较类似,通常用法是将一个可迭代对象逐一赋值给循环变量,完成相应操作的过程。最基础的用法如下:

scala> for(i <- 1 to 3) println(i)
1
2
3


在for循环内部,还可以直接嵌套逻辑判断条件,术语说法叫做循环守卫,即仅当条件满足时才进入循环体执行,否则进入下一循环:


scala> for(i <- 1 to 3 if(i%2==1)) print(i)
1
3


除了嵌套逻辑条件判断,还可以增加一些附属操作,仅仅是为了便于后续循环体执行,对循环执行不产生任何影响:


scala> for(i <- 1 to 3; j=2*i) println(j)
2
4
6


注意在循环变量与附属操作之间,需用";"做以分割,表示这是两句代码。而在前述的循环守卫中则可加可不加,且一般情况下不加";"更为直观。


对于嵌套循环,除了类似其他编程语言中的书写两重for循环外,还可直接将两层循环变量写到一个for循环中,功能一致但逻辑更为清晰:


// 嵌套for循环常规写法
scala> for(i <- 1 to 3) for(j <- 1 to i) println(i*j)
1
2
4
3
6
9
// 精简写法
scala> for(i <- 1 to 3; j <- 1 to i) println(i*j)
1
2
4
3
6
9


for循环在Scala中仍然属于一个代码块,所以其实也是有返回值的。应用这一特性,for循环其实还有另一个巧妙的运用:由一个迭代器生成另一个迭代器,功能类似于Python中的列表推导式。实现这一功能,需要配合使用关键yield:


scala> val nums = (for(i <- 1 to 5) yield i*2).toList
val nums: List[Int] = List(2, 4, 6, 8, 10)


2)while循环。一般而言,对于具有明确次数的循环结构采取for循环比较合适,而对于循环次数未知、需根据循环执行结果判断是否继续执行的情况则选用while循环更为合适。Scala中的while循环与其他编程语言中while用法几乎完全一致:


scala> var sum = 0
var sum: Int = 0
scala> var i = 0
var i: Int = 0
scala> while(sum<10){println(i); sum+=i; i+=1}
0
1
2
3
4


不过,除了使用场景的不同,Scala中while循环与for循环的另一个技术细节上的区别在于:for循环作为一个代码块是有对应返回值的(虽然可能返回值可能为空),而while循环则一定没有返回值(或者说返回值一定为空)。这一区别意味着:for循环既可以用于迭代产生新的迭代结果,也可以依靠历次循环产生相应的效果(即执行循环体带来副作用),而while循环则只能靠循环产生的副作用来实现功能。例如,模拟前面使用for循环+yield产生新的迭代器的过程,强行使用while循环实现如下:


scala> val arr = new Array[Int](3)
val arr: Array[Int] = Array(0, 0, 0)
scala> var i = 1
var i: Int = 1
scala> while(i<=3) {arr(i-1) = i*2; i+=1}
scala> arr
val res3: Array[Int] = Array(2, 4, 6)


3)do……while循环。do……while循环在实际工作中使用还是比较少的,其使用方法与while循环十分类似,唯一的区别在于while循环是先判断后执行;而do……while循环则是先执行再判断,所以无论如何do……while会至少执行一次。


最后值得指出的是,与其他编程语言不同,在Scala中并没有break和continue两个关键字,即无法简单实现循环中止或者跳过本次循环这一逻辑。虽然取以代之提供了break()方法,但用起来终究还是不够方便。那如果就是要实现break和continue两个需求呢,实际上Scala中可以灵活选用如下3种方式:

  • 增加if条件判断
  • for循环中设置循环守卫
  • while循环中增加相应的判断逻辑


03 小结


控制结构是编写任何程序都不得不涉及到的一个概念,对于常用的分支结构、循环结构在Scala中都有所体现,且均具有一定特色,灵活掌握还是比较方便的。


640.png






目录
相关文章
|
机器学习/深度学习 算法 决策智能
智能解决装箱问题:使用优化算法实现高效包装
装箱问题(Bin Packing Problem)是组合优化领域中的一个经典问题,主要涉及如何将一系列对象高效地装入有限数量的容器(或“箱”)中,同时满足特定的约束条件。这个问题的目标是最小化所需使用的箱子数量或者最大化箱子的装载效率,以减少空间或资源的浪费。
|
缓存 负载均衡 关系型数据库
Pgpool-II实现高可用+读写分离+负载均衡(一)---- 规划及安装
Pgpool-II是一款工作在PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件。提供了连接池、复制、负载均衡、限制过多连接、看门狗、查询缓存等功能。
|
JavaScript
vue关于通过下标更改数组的理解
vue关于通过下标更改数组的理解
|
数据库连接 数据库 Android开发
Android -- Room简化数据库设置图书案例
Android -- Room简化数据库设置图书案例
142 0
|
8月前
|
人工智能 API 开发者
阿里CEO吴泳铭-2024互联网大会发言:AI的最大价值是推动生产力变革
11月21日,2024年世界互联网大会“互联网企业家论坛”在乌镇召开。阿里巴巴CEO吴泳铭表示,AI的最大价值在于推动各行各业的生产力变革,而非仅限于开发超级APP。他强调,发展AI需建设繁荣的技术、产品和市场生态。目前,30多万家企业已接入阿里“通义”大模型,应用于代码开发、药物研发等场景。阿里巴巴坚持开源路线,全球开发者基于“通义千问”开发的衍生模型已突破7.8万个。吴泳铭认为,AI的发展需要行业共同努力,建设繁荣生态以实现高质量持续发展。
|
11月前
|
监控 小程序 前端开发
小程序全栈开发中的WebSocket实时通信实践
【10月更文挑战第3天】随着移动互联网的发展,小程序因便捷的用户体验和社交传播能力,成为企业拓展业务的新渠道。本文探讨了小程序全栈开发中的WebSocket实时通信实践,包括其实时通信、长连接及双向通信的特点,并通过实时聊天、推送、游戏和监控等功能的实现,展示了WebSocket在小程序中的应用。开发者需注意安全性、性能及兼容性等问题,以保障小程序的稳定运行和用户体验。
211 7
|
消息中间件 搜索推荐 UED
Elasticsearch 作为推荐系统后端的技术架构设计
【8月更文第28天】在现代互联网应用中,推荐系统已经成为提高用户体验和增加用户粘性的重要手段之一。Elasticsearch 作为一个高性能的搜索和分析引擎,不仅能够提供快速的全文检索能力,还可以通过其强大的数据处理和聚合功能来支持推荐系统的实现。本文将探讨如何利用 Elasticsearch 构建一个高效且可扩展的推荐系统后端架构,并提供一些具体的代码示例。
806 0
|
存储 缓存 网络协议
SYN Flood是什么?这篇给你讲明白!
SYN Flood是1994年发现的DDoS攻击方式,利用TCP三次握手的漏洞,通过发送大量伪造源IP的SYN报文,使服务器创建半连接,耗尽资源,导致服务中断。防御策略包括源认证、首包丢弃和使用Anti-DDoS系统。高防服务器和抗D盾等解决方案提供DDoS清洗和CC攻击防御,通过智能分布式云接入隐藏真实IP,保持TCP连接稳定,同时提供网络加速和防掉线功能。
|
Web App开发 XML 前端开发
CSS基础-超详解 (1)
CSS基础-超详解 (1)
77 0
|
机器学习/深度学习 编解码 PyTorch
手机图像去噪
NAFNet是一个没有激活函数的神经网络。目前,在图像修复领域有多种类型的网络结构。