跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Scala

Scala 流程控制:分支与循环

综述由AI生成Scala 流程控制包含顺序、分支与循环结构。分支使用 if 表达式,具有返回值并可替代三元运算符。循环支持 for 推导式、守卫及嵌套写法,while 用于可变变量迭代。Scala 3 移除了 do-while,中断需借助 Breaks 库。文章提供九九乘法表等综合案例及练习题解析,涵盖类型推断、Unit 类型等细节,帮助掌握函数式编程风格下的流程控制。

月光旅人发布于 2026/2/8更新于 2026/6/144.5K 浏览
Scala 流程控制:分支与循环

Scala 流程控制:分支与循环

在掌握了 Scala 的基础语法和数据类型之后,我们接下来将深入学习如何控制程序的执行流程。本节将详细探讨 Scala 中的分支和循环结构,领略到 Scala 在流程控制方面独特的、富有表现力的设计。

一、流程控制结构

顺序结构: 代码默认按照从上到下、从左到右的顺序执行。这是最基本的执行模式,无需特殊语法。

分支结构 (if): 根据条件决定代码执行路径。if 语句用于基于一个布尔表达式的结果来选择性地执行代码块。

分支类型语法示例
单分支if (condition) { ... }if (age >= 18) { println("Adult") }
双分支if (condition) { ... } else { ... }if (score >= 60) { println("Pass") } else { println("Fail") }
多分支if ... else if ... else ...if (grade == 'A') { ... } else if (grade == 'B') { ... } else { ... }
嵌套分支在一个 if 结构中嵌入另一个if (isLogin) { if (isAdmin) { ... } }

if 表达式: Scala 中的 if 语句是表达式,具有返回值。这个特性可以用来替代 Java 中的三元运算符。if 表达式的返回值是被执行分支中最后一个表达式的值。

代码案例

// 单分支
val age = 20
if (age >= 18) {
  println("此人是成年人 (Adult)")
}

// 双分支
val score = 55
if (score >= 60) {
  println("考试通过 (Pass)")
} else {
  println("考试未通过 (Fail)")
}

// 多分支
val grade = 'B'
if (grade == 'A') {
  println("优秀 (Excellent)")
} else if (grade == 'B') {
  println("良好 (Good)")
} else if (grade == 'C') {
  println("及格 (Average)")
} else {
  println("需要努力 (Needs Improvement)")
}

// 嵌套分支
val isLogin = true
val isAdmin = false
if (isLogin) {
  println("用户已登录。")
  if (isAdmin) {
    println("欢迎管理员!拥有所有权限。")
  } else {
    println("欢迎普通用户!拥有受限权限。")
  }
} else {
  println("用户未登录,请先登录。")
}

// if 表达式返回值
val temperature = 25
val weatherDescription = if (temperature > 30) "炎热"
else if (temperature < 10) "寒冷"
else "温和"
println(s"今天天气:$weatherDescription")

val x = 10
// 使用 if 表达式给常量赋值
val result = if (x > 0) "positive" else "non-positive"
println(result) // 输出:positive

val score2 = 85
val grade2 = if (score2 >= 90) 'A'
else if (score2 >= 80) 'B'
else 'C'
println(s"Grade is: $grade2") // 输出:Grade is: B

块表达式 ({}):

  • 使用花括号 {} 包围的多行代码构成一个块表达式。
  • 块表达式的值是其最后一个语句的值。

代码案例

val a = 5
val b = 10
val blockResult = {
  println("Calculating...")
  val sum = a + b
  sum // 块表达式的最后一个语句是 sum, 所以它的值被赋给 blockResult
}
println(s"The result from the block is: $blockResult") // 输出 15

二、循环结构

for 循环

Scala 的 for 循环远比传统命令式语言的 for 循环更灵活,它更像一个'生成器'。

for 循环特性语法/示例说明
遍历范围 (Range)for (i <- 1 to 10)
for (i <- 1 until 10)
to 包含上界 (1-10)。
until 不包含上界 (1-9)。
循环守卫 (Guard)for (i <- 1 to 10 if i % 2 == 0)在遍历过程中加入 if 条件进行过滤,只有满足条件的元素才会被处理。
嵌套循环for (i <- 1 to 3; j <- 1 to 3)可以将多个生成器用分号隔开写在同一行,代码更紧凑。
for 推导式 (Comprehension)val squares = for (i <- 1 to 5) yield i * i使用 yield 关键字,将 for 循环的每次迭代结果收集起来,构建成一个新的集合。

代码案例

// 遍历范围并使用循环守卫
println("偶数 in 1 to 10:")
for (i <- 1 to 10 if i % 2 == 0) {
  print(s"$i ")
}
println()

// 嵌套循环打印坐标
println("坐标:")
for (i <- 1 to 2; j <- 'a' to 'b') {
  println(s"($i, $j)")
}

// for 推导式生成一个 List[Int]
val squares = for (i <- 1 to 5) yield i * i
println(s"Squares: $squares") // 输出:Squares: List(1, 4, 9, 16, 25)

while 循环

格式: while (condition) { ... }

var i = 5
while (i > 0) {
  println(i)
  i -= 1
}

do-while 循环

语法 (Scala 2):

// do {
//   // 循环体
// } while (condition)

重要说明: do-while 语句在 Scala 3 中已被移除。由于它在实践中使用较少且不符合函数式编程的表达式风格,Scala 3 将其废弃。任何 do-while 逻辑都可以用 while 循环或其他结构等价实现。

代码案例 (Scala 2):

// 以下代码仅在 Scala 2.x 环境中有效
var j = 5
do {
  println(j)
  j -= 1
} while (j > 0)

循环中断

Scala 本身没有内置的 break 和 continue 关键字,因为这鼓励使用更函数式的编程风格 (如使用过滤器、递归等)。但如果确实需要,可以通过标准库模拟。

标准做法: 导入 scala.util.control.Breaks,并使用 breakable 和 break() 方法。 实现 break: 将整个循环用 breakable 代码块包裹。 实现 continue: 将循环体内部需要跳过的部分用 breakable 包裹。

代码案例 (模拟 break)

import scala.util.control.Breaks._

println("寻找第一个大于 5 的偶数:")
breakable {
  for (i <- 1 to 10) {
    if (i % 2 == 0 && i > 5) {
      println(s"找到了:$i")
      break // 中断 breakable 代码块,即跳出循环
    }
  }
}

代码案例 (模拟 continue)

import scala.util.control.Breaks._

println("\n打印 1 到 10 之间的所有奇数:")
for (i <- 1 to 10) {
  breakable {
    // 这个 breakable 块放在循环内部,用于模拟 continue
    if (i % 2 == 0) {
      break // 当 i 是偶数时,跳出内部的 breakable 块
    }
    println(s"奇数:$i") // 这行代码只在 i 是奇数时执行
  }
}

三、综合案例:打印九九乘法表

这个经典案例很好地展示了嵌套循环和字符串格式化的应用。

方法一:传统嵌套 for 循环

println("--- 九九乘法表 (传统嵌套 for) ---")
for (i <- 1 to 9) {
  for (j <- 1 to i) {
    print(s"$j * $i = ${i * j}\t")
  }
  println() // 每行结束后换行
}

方法二:使用分号的紧凑型嵌套 for 循环

println("\n--- 九九乘法表 (紧凑型 for) ---")
for (i <- 1 to 9; j <- 1 to i) {
  print(s"$j * $i = ${i * j}\t")
  if (j == i) println() // 当内层循环结束时换行
}

解析: 这种紧凑写法将两个生成器放在同一行。if (j == i) 这个判断是关键,它确保了只在每一行的最后一个表达式打印完毕后才执行换行操作。

练习题

题目一:if 表达式
编写一段代码,使用 if 表达式判断一个整数 num 是正数、负数还是零,并将结果 ('positive', 'negative', 'zero') 赋值给一个 val 变量 sign。

题目二:for 循环与 to
使用 for 循环打印出从 5 到 1 (递减) 的所有整数。

题目三:for 循环与 until
使用 for 循环打印出 100 以内的所有 7 的倍数 (不包含 100)。

题目四:循环守卫
使用 for 循环和循环守卫,找出 1 到 50 之间所有既能被 3 整除又能被 5 整除的数。

题目五:嵌套 for 循环
使用嵌套的 for 循环打印一个 4x4 的星号 * 矩阵。

题目六:for 推导式 (生成新集合)
使用 for 推导式,将一个 List("apple", "banana", "cherry") 转换为一个新的 List,其中每个单词都变成大写。

题目七:while 循环
使用 while 循环计算 1 到 100 的所有整数之和。

题目八:模拟 break
给定一个 List(1, 4, 9, 16, 25, 36, 49),使用 breakable 和 break 找到并打印出第一个大于 30 的数后立即停止循环。

题目九:块表达式返回值
编写一个块表达式,它接收两个变量 x 和 y,在内部计算它们的平方和 (x*x + y*y),并将这个结果作为块表达式的值赋给一个 val 变量 result。

题目十:if 表达式的类型
分析以下代码,result 的类型会被推断为什么?并解释原因。

val condition = true
val result = if (condition) 100 else "Error"

题目十一:for 循环步长
使用 for 循环和 by 关键字,打印出从 0 到 20,步长为 5 的所有数字 (0, 5, 10, 15, 20)。

题目十二:for 推导式与守卫
给定一个 List(1, 2, 3, 4, 5, 6),使用 for 推导式和循环守卫,生成一个新的 List,其中只包含原列表中偶数的平方。

题目十三:if 表达式与 Unit 类型
分析以下代码,result 的值和类型是什么?

val result = if (false) "Success"

题目十四:模拟 continue
使用 breakable 和 break 模拟 continue 的效果:打印 1 到 10 中所有的奇数。

题目十五:综合应用 (FizzBuzz)
编写一个程序,使用 for 循环遍历 1 到 100。对于每个数字,使用 if-else if-else 结构判断:

  • 如果数字能被 15 整除,打印 'FizzBuzz'。
  • 如果只能被 3 整除,打印 'Fizz'。
  • 如果只能被 5 整除,打印 'Buzz'。
  • 否则,打印数字本身。

答案与解析

答案一:

val num = -5
val sign = if (num > 0) "positive"
else if (num < 0) "negative"
else "zero"
println(s"The sign of $num is: $sign")

解析: if-else if-else 结构作为表达式,其结果可以直接赋值给 sign 变量。

答案二:

for (i <- 5 to 1 by -1) {
  println(i)
}

解析: for 循环可以通过 by 关键字指定步长,步长为负数时即为递减。

答案三:

for (i <- 1 until 100 if i % 7 == 0) {
  println(i)
}

解析: until 创建了一个不包含上界 (100) 的范围,循环守卫 if i % 7 == 0 过滤出了 7 的倍数。

答案四:

for (i <- 1 to 50 if i % 3 == 0 && i % 5 == 0) {
  println(i)
}

解析: 循环守卫可以包含复杂的逻辑条件,如使用 && (与)。

答案五:

for (i <- 1 to 4) {
  for (j <- 1 to 4) {
    print("* ")
  }
  println() // 每行结束后换行
}

解析: 外层循环控制行数,内层循环控制每行打印的星号数量。

答案六:

val words = List("apple", "banana", "cherry")
val upperWords = for (word <- words) yield word.toUpperCase
println(upperWords) // 输出:List(APPLE, BANANA, CHERRY)

解析: for-yield 结构遍历 words 列表,对每个元素 word 应用 .toUpperCase 方法,并将结果收集到一个新的 List 中。

答案七:

var sum = 0
var i = 1
while (i <= 100) {
  sum += i
  i += 1
}
println(s"The sum is: $sum")

解析: 经典的 while 循环用法,需要一个可变的循环控制变量 i 和累加变量 sum。

答案八:

import scala.util.control.Breaks._
val numbers = List(1, 4, 9, 16, 25, 36, 49)
breakable {
  for (num <- numbers) {
    if (num > 30) {
      println(s"Found number greater than 30: $num")
      break
    }
  }
}

解析: breakable 包裹了整个循环,当 num > 30 条件满足时,break 会中断 breakable 块的执行,从而跳出循环。

答案九:

val x = 3
val y = 4
val result = {
  println("Performing calculation...")
  val xSquare = x * x
  val ySquare = y * y
  xSquare + ySquare // 这是块的最后一个表达式,它的值将赋给 result
}
println(result) // 输出 25

解析: 块表达式的值由其最后一个表达式 xSquare + ySquare 决定。

答案十:
result 的类型会被推断为 Any。

解析: Scala 的 if-else 表达式的返回类型是两个分支返回类型的最近公共父类型。100 的类型是 Int,"Error" 的类型是 String。Int 和 String 的最近公共父类型是 Any。

答案十一:

for (i <- 0 to 20 by 5) {
  println(i)
}

解析: by 关键字用于指定循环的步长。

答案十二:

val numbers = List(1, 2, 3, 4, 5, 6)
val evenSquares = for (n <- numbers if n % 2 == 0) yield n * n
println(evenSquares) // 输出:List(4, 16, 36)

解析: for-yield 结合循环守卫,先通过 if n % 2 == 0 过滤出偶数,然后 yield 出它们的平方。

答案十三:
result 的值是 () (Unit 的实例),类型是 Any。

解析: 这个 if 语句没有 else 分支。当条件为 false 时,if 语句没有返回值。在 Scala 中,这种情况的'无返回值'由 Unit 类型表示。因此,整个 if 表达式的类型是 String 和 Unit 的最近公共父类型,即 Any。

答案十四:

import scala.util.control.Breaks._
for (i <- 1 to 10) {
  breakable {
    if (i % 2 == 0) {
      break // 如果是偶数,中断 breakable 块,效果类似 continue
    }
    println(i) // 这行代码只在 i 是奇数时执行
  }
}

解析: 将 breakable 块放在循环体内部。当满足某个条件时调用 break,只会跳出当前的 breakable 块,然后继续下一次循环,从而模拟了 continue 的效果。

答案十五:

for (i <- 1 to 100) {
  if (i % 15 == 0) {
    println("FizzBuzz")
  } else if (i % 3 == 0) {
    println("Fizz")
  } else if (i % 5 == 0) {
    println("Buzz")
  } else {
    println(i)
  }
}

解析: 这是一个经典的编程问题。关键在于首先检查能被 15 (3 和 5 的最小公倍数) 整除的条件,因为如果先检查 3 或 5,那么 15 的倍数就会被错误地归类。

目录

  1. Scala 流程控制:分支与循环
  2. 一、流程控制结构
  3. 代码案例
  4. 代码案例
  5. 二、循环结构
  6. for 循环
  7. 代码案例
  8. while 循环
  9. do-while 循环
  10. 循环中断
  11. 代码案例 (模拟 break)
  12. 代码案例 (模拟 continue)
  13. 三、综合案例:打印九九乘法表
  14. 方法一:传统嵌套 for 循环
  15. 方法二:使用分号的紧凑型嵌套 for 循环
  16. 练习题
  17. 答案与解析
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 时代技术民主化:文科生为何成最大受益者
  • C++ 从零实现 TCP Socket 网络工具实战
  • Linux 互斥锁详解:临界区保护与多线程协作
  • 大模型高效微调 LoRA 原理详解与训练过程分析
  • 麒麟 Wine 助手:利用 AI 自动配置 Windows 应用
  • Python 编程入门教程:从零基础到高级应用详解
  • Cursor Chat Browser:管理 AI 聊天历史的 Web 应用
  • SQL 性能优化:连接条件下推技术原理与实践
  • SenseVoiceSmall 语音识别 WebUI 快速部署与使用指南
  • DevEco Studio 云函数开发、调试与部署指南
  • VSCode Java 项目 JDK 配置与版本切换指南
  • Git 本地身份配置:用户名与邮箱设置详解
  • 豆包 Seedream 4.0 多图融合技术解析与实战测评
  • Webnovel Writer:基于 Claude Code 的长篇网文 AI 创作系统
  • VSCode Copilot 配置使用 DeepSeek
  • HTML 核心语法和常用标签
  • GLM-5 大模型代码生成能力深度评测与实战
  • VSCode 集成 DeepSeek 模型接入 Copilot 实战
  • Flask 框架从入门到实战完整指南
  • 基于 Stable Diffusion 制作上世纪 90 年代游戏美术风格

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online