1. 程式人生 > 其它 >Scala流程控制語句

Scala流程控制語句

[toc]

## Scala流程控制語句

> 1. 在程式中,程式執行的流程控制決定程式是如何執行的,是我們必須掌握的,主要有三大流程控制語句。
> 2. ==Scala語言中控制結構和Java語言中的控制結構基本相同==,在不考慮特殊應用場景的情況下,程式碼書寫方式以及理解方式都沒有太大的區別。
> 1. 順序控制
> 2. 分支控制
> 3. 迴圈控制

### 1. 順序控制

> 程式從上到下逐行地執行,中間沒有任何判斷和跳轉。
>
> ~~~scala
> //Scala中定義變數時採用合法的前向引用。如:
> def main(args : Array[String]) : Unit = {
> var num1 = 12
> var num2 = num1 + 2
> }
> //錯誤形式:
> def main(args : Array[String]) : Unit = {
> var num2 = num1 + 2
> var num1 = 12
> }
> ~~~
>
> ![image-20210323200717370](assets/image-20210323200717370.png)

### 2. 分支控制

> 讓程式有選擇的的執行,分支控制有三種(與Java相同):
>
> 1. 單分支
> 2. 雙分支
> 3. 多分支

#### 單分支和雙分支

~~~scala
import scala.io.StdIn
/**
* @Date 2021/3/23 16:33
* @Version 10.21
* @Author DuanChaojie
*/
object IfDemo01 {
/**
* 小技巧:如何乍看某個包下包含的內容?
* 1、比如我們想看 scala.io 包有什麼內容的話
* 2、強游標放在io上即可,輸入ctrl + b
* 3、強游標放在StdIn上即可,輸入ctrl + b看的是StdIn原始碼
* @param args
*/
def main(args: Array[String]): Unit = {

println("請輸入年齡:")
val age = StdIn.readInt()
if (age > 18) {
println("您已經成年!")
} else {
println("小屁孩一個")
}
}
}
~~~

> 單分支和雙分支課後題

~~~scala
/**
* @Date 2021/3/23 16:40
* @Version 10.21
* @Author DuanChaojie
*/
object IfElseExercise01 {
def main(args: Array[String]): Unit = {
test1(11, 111)
test2(111.0, 11.0)
test3(12, 3)
test4(2000)
}


/**
* 編寫程式,宣告2個Int型變數並賦值。判斷兩數之和,如果大於等於50,列印“hello world!”
*
* @param n1
* @param n2
*/
def test1(n1: Int, n2: Int): Unit = {
if (n1 + n2 >= 50) {
println("hello world!")
}
}

/**
* 編寫程式,宣告2個Int型變數並賦值。判斷兩數之和,如果大於等於50,列印“hello world!”
*
* @param d1
* @param d2
*/
def test2(d1: Double, d2: Double): Unit = {
if (d1 > 10.0 && d2 < 20.0) {
println(d1 + d2)
}
}

/**
* 定義兩個變數Int,判斷二者的和,是否既能被3又能被5整除,列印提示資訊
*
* @param n1
* @param n2
*/
def test3(n1: Int, n2: Int): Unit = {
var sum = n1 + n2
if (sum % 3 == 0 && sum % 5 == 0) {
println(s"$n1+$n2 既能被3整除又能被5整除")
}
}

/**
* 判斷一個年份是否是閏年,閏年的條件是符合下面二者之一:
* (1)年份能被4整除,但不能被100整除;(2)能被400整除
*
* @param year
*/
def test4(year: Int): Unit = {
if (year < 0) {
println("請輸入合理的年份!")
} else {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
println(s"$year 年是閏年")
}
}
}
}
~~~

#### 多分支

~~~~scala
import scala.io.StdIn

/**
* @Date 2021/3/23 16:54
* @Version 10.21
* @Author DuanChaojie
*/
object IfDemo02 {
def main(args: Array[String]): Unit = {
/**
* 嶽小鵬參加scala考試,他和父親嶽不群達成承諾:
* 如果:
* 成績為100分時,獎勵一輛BMW;
* 成績為(80,99]時,獎勵一臺iphone7plus;
* 當成績為[60,80]時,獎勵一個 iPad;
* 其它時,什麼獎勵也沒有。
* 成績是從控制檯輸入
**/
println("請輸入成績")
val score = StdIn.readDouble()
if (score == 100) {
println("成績為100分時,獎勵一輛BMW")
//寫法1使用範圍,寫法2就是嚴格的判斷
} else if (score > 80 && score <= 99) {
println("成績為(80,99]時,獎勵一臺iphone7plus")
} else if (score >= 60 && score <= 80) {
println("獎勵一個 iPad")
} else {
println("沒有任何獎勵")
}
}
}
~~~~

> 多分支課後題:
>
> ~~~~scala
> /*
> 求ax2+bx+c=0方程的根。a,b,c分別為函式的引數,
> 如果:
> b2-4ac>0,則有兩個解;
> b2-4ac=0,則有一個解;
> b2-4ac<0,則無解;
> [a=3 b=100 c=6]
> 提示1:
> x1=(-b+sqrt(b2-4ac))/2a
> X2=(-b-sqrt(b2-4ac))/2a
> 提示2:
> sqrt(num) 在 scala 包中(預設引入的) 的math 的包物件有很多方法直接可用.
> */
> ~~~~

~~~~scala
/**
* @Date 2021/3/23 17:02
* @Version 10.21
* @Author DuanChaojie
*/
object IfElseExercise02 {
def main(args: Array[String]): Unit = {

/**
思路的分析
1. 定義三個變數a,b,c
2. 使用多分支完成
3. 因為 b2-4ac會多次使用,因此我們可以先計算,並保持到變數中
4. 判斷,寫邏輯
*/

val a = 3
val b = 100
val c = 6
val m = b * b - 4 * a * c
var x1 = 0.0
var x2 = 0.0

if (m > 0) {
x1 = (-b + Math.sqrt(m)) / 2 * a
x2 = (-b - Math.sqrt(m)) / 2 * a
println("有兩個解: \nx1=" + x1.formatted("%.2f") + "\nx2=" + x2.formatted("%.2f"))
} else if (m == 0) {
x1 = (-b + Math.sqrt(m)) / 2 * a
println("有一個解 x1=" + x1)
} else {
println("無解..")
}
}
}
~~~~

#### 分支控制if-else 注意事項

> 1. `如果大括號{}內的邏輯程式碼只有一行,大括號可以省略, 這點和java 的規定一樣。`
> 2. Scala中任意表達式都是有返回值的,也就意味著if else表示式其實是有返回結果的,具體返回結果的值取決於滿足條件的程式碼體的最後一行內容。
> 3. Scala中是沒有三元運算子,因為 Scala 的if-else 是有返回值的,因此,本身這個語言也不需要三元運算子了,並且可以寫在同一行,類似 三元運算

~~~scala
/**
* @Date 2021/3/23 17:11
* @Version 10.21
* @Author DuanChaojie
*/
object IfElseExercise03 {
def main(args: Array[String]): Unit = {
var sumVal = 9
val result = if (sumVal > 20) {
"結果大於20"
}
//返回的是() 即 Unit
println("res=" + result)
}
}
~~~

#### 巢狀分支

> 在一個分支結構中又完整的嵌套了另一個完整的分支結構,裡面的分支的結構稱為內層分支外面的分支結構稱為外層分支。==巢狀分支不要超過3層==
>
> 案例一:

~~~scala
/**
* @Date 2021/3/23 17:13
* @Version 10.21
* @Author DuanChaojie
*/
object IfElseExercise04 {
def main(args: Array[String]): Unit = {
/**
* 參加百米運動會,如果用時8秒以內進入決賽,否則提示淘汰。
* 並且根據性別提示進入男子組或女子組。
* 【可以讓學員先練習下5min】, 輸入成績和性別,進行判斷。
*/
println("請輸入運動員的成績:")
val speed = StdIn.readDouble()
if (speed <= 8) {
println("請輸入性別")
val gender = StdIn.readChar()
if (gender == '男') {
println("進入男子組")
} else {
println("進入女子組")
}
} else {
println("你被淘汰...")
}
}
}
~~~

> 案例二:

~~~scala
/**
* @Date 2021/3/23 17:16
* @Version 10.21
* @Author DuanChaojie
*/
object IfElseExercise05 {
def main(args: Array[String]): Unit = {

/**
應用案例2
出票系統:根據淡旺季的月份和年齡, 列印票價 [考慮學生先做5min]
4_10 旺季:
成人(18-60):60
兒童(<18):半價
老人(>60):1/3
淡季:
成人:40
其他:20
思路分析
1. 定義至少三個變數 month , age, ticket
2. 邏輯上有月份和年齡的判斷因此,會使用巢狀分支
3. 根據對應的業務邏輯完成程式碼
*/
println("輸入月份")
val month = StdIn.readInt()
println("輸入年齡")
val age = StdIn.readInt()
val tikcet = 60

if (month >= 4 && month <= 10) {
if (age >= 18 && age <= 60) {
println("你的票價是" + tikcet)
} else if (age < 18) {
println("你的票價是" + tikcet / 2)
} else {
println("你的票價是" + tikcet / 3)
}
} else {
if (age >= 18 && age <= 60) {
println("你的票價是" + 40)
} else {
println("你的票價是" + 20)
}
}
}
}
~~~

#### switch分支結構TODO

> 在Scala中沒有switch,而是使用`模式匹配`來處理。
>
> 模式匹配涉及到的知識點較為綜合,因此我們放在==後面講解。==

### 3. 迴圈控制

#### ☆for迴圈控制☆

> ==Scala 也為for 迴圈這一常見的控制結構提供了非常多的特性==,這些for 迴圈的特性被稱為for 推導式(for comprehension)或for 表示式(for expression)
>
> 範圍資料迴圈方式1

~~~~scala
/**
* @Date 2021/3/23 17:34
* @Version 10.21
* @Author DuanChaojie
*/
object ForDemo01 {
def main(args: Array[String]): Unit = {
//輸出10句 "hello,尚矽谷!"
val start = 1
val end = 10
//說明
//1. start 從哪個數開始迴圈
//2. to 是關鍵字
//3. end 迴圈結束的值
//4. start to end 表示前後閉合
for (i <- start to end) {

println("你好,尚矽谷" + i)
}

//說明for 這種推導時,也可以直接對集合進行遍歷
var list = List("hello", 10, 30, "tom")
for (item <- list) {
println("item=" + item)
}

}
}
~~~~

> 範圍資料迴圈方式2

~~~scala
/**
* @Date 2021/3/23 17:38
* @Version 10.21
* @Author DuanChaojie
*/
object ForUntilDemo02 {
def main(args: Array[String]): Unit = {
//輸出10句 "hello,尚矽谷!"
val start = 1
val end = 11
// 迴圈的範圍是 start --- (end - 1)
for (i <- start until end) {
println("你好,尚矽谷" + i)
}
}
}
~~~

> `迴圈守衛,即迴圈保護式(也稱條件判斷式,守衛)。保護式為true則進入迴圈體內部,為false則跳過,類似於continue`

~~~scala
object ForGuard {
def main(args: Array[String]): Unit = {
for (i <- 1 to 3 if i != 2) {
println("i = " + i)
}
}
}
~~~

> 引入變數

~~~scala
object ForVar {
def main(args: Array[String]): Unit = {
for (i <- 1 to 3; j = 4 - i) {
println("j = " + j)
}
}
}
~~~

> 巢狀迴圈

~~~~scala
object ForMulti {
def main(args: Array[String]): Unit = {
for (i <- 1 to 3; j <- 1 to 3) {
println("i = " + i + "\tj = " + j)
}

println("----------------------------")
// 上面的寫法也可以寫成:
for (i <- 1 to 3) {
for (j <- 1 to 3) {
println("i = " + i + "\tj = " + j)
}
}
}
}
~~~~

> 迴圈返回值:
>
> - 將遍歷過程中處理的結果返回到一個新Vector集合中,使用yield關鍵字
> - `val res = for(i <- 1 to 10) yield i`

~~~~scala
object ForYield {
def main(args: Array[String]): Unit = {
/**
* 說明 val res = for(i <- 1 to 10) yield i 含義
* 1. 對1 to 10 進行遍歷
* 2. yield i 將每次迴圈得到i 放入到集合Vector中,並返回給res
* 3. i 這裡是一個程式碼塊,這就意味我們可以對i進行處理
* 4. 下面的這個方式,就體現出scala一個重要的語法特點,就是將一個集合中個各個資料
* 進行處理,並返回給新的集合
*/
val res = for(i <- 1 to 10) yield {
if(i % 2 == 0){
i
}else{
"不是偶數"
}
}
// Vector(不是偶數, 2, 不是偶數, 4, 不是偶數, 6, 不是偶數, 8, 不是偶數, 10)
println(res)
}
}
~~~~

> `使用花括號{}代替小括號()`
>
> ~~~scala
> //基本案例
> for(i <- 1 to 3; j = i * 2) {
> println(" i= " + i + " j= " + j)
> }
>
> //可以寫成
> for{
> i <- 1 to 3
> j = i * 2} {
> println(" i= " + i + " j= " + j)
> }
> ~~~
>
> 對基本案例說明
>
> 1. {}和()對於for表示式來說都可以
> 2. for 推導式有一個不成文的約定:當for 推導式僅包含單一表達式時使用圓括號,當其包含多個表示式時使用大括號
> 3. 當使用{} 來換行寫表示式時,分號就不用寫了
>
> 注意事項和細節說明
>
> 1. ==Scala 的for迴圈形式和java是較大差異,這點請同學們注意,但是基本的原理還是一樣的。==
> 2. 思考題:如何使用迴圈守衛控制步長?

~~~scala
/**
* @Date 2021/3/23 20:42
* @Version 10.21
* @Author DuanChaojie
*/
object ForStep {
def main(args: Array[String]): Unit = {

for (i <- 1 to 10) {
println("i=" + i)
}

//步長控制為2
println("-------------")

/**
* Range(1,10,2)的對應的構建方法是
* def apply(start: Int, end: Int, step: Int): Range = new Range(start, end, step)
*/
for (i <- Range(1, 10, 2)) {
println("i=" + i)
}

//控制步長的第二種方式-for迴圈守衛
println("**************************")
for (i <- 1 to 10 if i % 2 == 1) {
println("i=" + i)
}
}
}
~~~

> For迴圈練習題

~~~scala

/**
* @Date 2021/3/23 19:08
* @Version 10.21
* @Author DuanChaojie
*/
object ForExercise01 {
def main(args: Array[String]): Unit = {
/**
for迴圈練習題:
列印1~100之間所有是9的倍數的整數的個數及總和.
完成下面的表示式輸出
*/
val start = 1
val end = 100
var count = 0
var sum = 0

for (i <- start to end) {
if (i % 9 == 0) {
count += 1
sum += i
}
}
printf("count=%d, sum=%d\n", count, sum)

//輸出加法的迴圈表示式
val num = 6
for (i <- 0 to num) {
printf("%d + %d = %d\n", i, (num - i), num)
}

var list = List(1,2)
}
}
~~~

#### while迴圈控制

~~~~scala
object WhileDemo01 {
def main(args: Array[String]): Unit = {
var i = 0
while(i < 10){
println("Hello 尚矽谷" + i)
// 迴圈變數迭代
i += 1
}
}
}
~~~~

> 注意事項和細節說明
>
> 1. 迴圈條件是返回一個布林值的表示式
> 2. while迴圈是先判斷再執行語句
> 3. 與If語句不同,While語句本身沒有值,即整個While語句的結果是Unit型別的()
> 4. 因為while中沒有返回值,所以當要用該語句來計算並返回結果時,就不可避免的使用變數 ,而變數需要宣告在while迴圈的外部,那麼就等同於迴圈的內部對外部的變數造成了影響,`所以不推薦使用,而是推薦使用for迴圈。`

#### do..while迴圈控制

~~~scala
object DoWhileDemo01 {
def main(args: Array[String]): Unit = {
var i = 0
do {
println(i + "Hello Scala")
i += 1
} while (i < 10)
}
}
~~~

> 注意事項和細節說明:
>
> 1. 迴圈條件是返回一個布林值的表示式
> 2. do..while迴圈是先執行,再判斷
> 3. 和while 一樣,因為do…while中沒有返回值,所以當要用該語句來計算並返回結果時,就不可避免的使用變數 ,而變數需要宣告在do...while迴圈的外部,那麼就等同於迴圈的內部對外部的變數造成了影響`,所以不推薦使用,而是推薦使用for迴圈`

#### 多重迴圈控制

> 1. 將一個迴圈放在另一個迴圈體內,就形成了巢狀迴圈。其中,for ,while ,do…while均可以作為外層迴圈和內層迴圈。`【建議一般使用兩層,最多不要超過3層】`
> 2. 實質上,巢狀迴圈就是把內層迴圈當成外層迴圈的迴圈體。當只有內層迴圈的迴圈條件為false時,才會完全跳出內層迴圈,才可結束外層的當次迴圈,開始下一次的迴圈。
> 3. 設外層迴圈次數為m次,內層為n次, 則內層迴圈體實際上需要執行m*n=mn次。
>
> `案例一:`

~~~~scala
object Exercise01 {
/**
*應用例項:
*1.統計三個班成績情況,每個班有5名同學,求出各個班的平均分和所有班級的平均分[學生的成績從鍵盤輸入]。
* 分析思路
* (1) classNum 表示 班級個數 , stuNum 表示學生個數
* (2) classScore 表示各個班級總分 totalScore 表示所有班級總分
* (3) score 表示各個學生成績
* (4) 使用迴圈的方式輸入成績
*2.統計三個班及格人數,每個班有5名同學。
*3.打印出九九乘法表
*/

def main(args: Array[String]): Unit = {
val classNum = 3
val stuNum = 5
var score = 0.0 //分數
var classScore = 0.0 //班級的總分
var totalScore = 0.0 //所有班級總分

for (i <- 1 to classNum) {
//先將 classScore 清0
classScore = 0.0
for (j <- 1 to stuNum) {
printf("請輸入第%d班級的第%d個學生的成績\n", i, j)
score = StdIn.readDouble()
classScore += score
}
//累計 totalScore
totalScore += classScore
printf("第%d班級的平均分為%.2f\n", i, classScore / stuNum)
}
printf("所有班級的平均分為%.2f", totalScore / (stuNum * classNum))
}
}
~~~~

> 案例二:

```scala
object Exercise02 {
def main(args: Array[String]): Unit = {
/**
* 2.統計三個班及格人數,每個班有5名同學。
*/
val classNum = 3
val stuNum = 5
var score = 0.0 //分數
var classScore = 0.0 //班級的總分
var totalScore = 0.0 //所有班級總分
var passNum = 0 //統計及格人數
for (i <- 1 to classNum) {
//先將 classScore 清0
classScore = 0.0
for (j <- 1 to stuNum) {
printf("請輸入第%d班級的第%d個學生的成績\n", i, j)
score = StdIn.readDouble()
if (score >= 60) {
passNum += 1
}
classScore += score
}
//累計 totalScore
totalScore += classScore
printf("第%d班級的平均分為%.2f\n", i, classScore / stuNum)
}
printf("所有班級的平均分為%.2f", totalScore / (stuNum * classNum))
printf("所有班級的及格人數為%d", passNum)
}
}
```

> 案例三:

~~~~scala
/**
* @Date 2021/3/23 19:44
* @Version 10.21
* @Author DuanChaojie
*/
object Exercice03 {
def main(args: Array[String]): Unit = {
//3.打印出九九乘法表
var num = 9
for (i <- 1 to num) {
for (j <- 1 to i) {
print(s"$j * $i = ${i * j} \t")
}
println()
}
}
}
~~~~

#### while迴圈的中斷

==Scala內建控制結構特地去掉了break和continue,是為了更好的適應函式化程式設計,推薦使用函式式的風格解決break和contine的功能,而不是一個關鍵字。==

~~~~scala
package com.atguigu.chapter04

import util.control.Breaks._

/**
* @Date 2021/3/23 19:48
* @Version 10.21
* @Author DuanChaojie
*/
object WhileBreak {
def main(args: Array[String]): Unit = {
//breakable()函式
//說明
//1. breakable 是一個高階函式:可以接收函式的函式就是高階函式(後面詳解)

//2. def breakable(op: => Unit) {
// try {
// op
// } catch {
// case ex: BreakControl =>
// if (ex ne breakException) throw ex
// }
// }
// (1) op: => Unit 表示接收的引數是一個沒有輸入,也沒有返回值的函式
// (2) 即可以簡單理解可以接收一段程式碼塊
// 3. breakable 對break()丟擲的異常做了處理,程式碼就繼續執行
// 4. 當我們傳入的是程式碼塊,scala程式設計師會將() 改成{}

var n = 0
breakable {
while (n <= 20) {
n += 1
println("n = " + n)
if (n == 18) {
break()
}
}
}
}
}
~~~~

> 如何實現continue的效果?Scala內建控制結構特地也去掉了continue,是為了更好的適應函式化程式設計,可以
>
> `使用if – else 或是迴圈守衛實現continue的效果。`

~~~~scala
object ContinueDemo {
def main(args: Array[String]): Unit = {
/**
* 1. 1 to 10
* 2. 迴圈守衛 if (i != 2 && i != 3) 這個條件為ture
* 才執行迴圈體,即當i ==2 或者 i == 3時,就跳過
*/
for (i <- 1 to 10 if (i != 2 && i != 3)) {
println("i=" + i)
}

//也可以寫成如下的形式
for (i <- 1 to 10) {
if (i != 2 && i != 3) {
println("i=" + i)
}
}
}
}
~~~~

## ☆