目錄
- 第二章 控制結構和函數
- 1- 條件表達式
- 2- 語句終止
- 3- 塊表達式和賦值
- 4- 輸入和輸出
- 5- 循環
- 6- 高級for循環和for推到式
- 7- 函數
- 8- 默認參數和帶名參數
- 9- 可變參數
- 10- 過程
- 11- 懶值
- 12- 異常
- end
第二章 控制結構和函數
1- 條件表達式
Scala的 if/esle 語法結構與java一樣, 但是在Scala中 if/else 表達式有值, 這個值就是跟在 if 或 else 之后表達式的值.
我們可以將 if/esle 表達式的值賦值于變量:
val x = 5val s = if (x > 0) 1 else -1println(s) // 1
// 等價于val x = 5var z = 0if (x > 0) z = 1 else z = -1println(z) // 1
相比較, 第一種寫法更好, 因為它可以用來初始化一個 val, 而第二種寫法中, z 必須是 var;
在Scala中, 每個表達式都有一個類型;
如果是混合類型, 則類型為 Any;
如果 else 部分缺失, 例如:
val y = -5val t = if (y > 0) 1println(t) // ()
等價于
val y = -5val t = if (y > 0) 1 else ()println(t) // ()
Scala沒有 Switch 語句, 但是它有一個更強大的模式匹配機制;
2- 語句終止
在Scala中, 語句的終止通常使用分號 (😉 來表示, 但是大多數情況下, 分號是可選的;
Scala具有自動分號插入(Automatic Semicolon Insertion) 的功能, 因此在大多數情況下, 可以省略分號而不會影響代碼的執行;
然而, 有一些情況下需要顯示使用分號來終止語句, 例如:
- 在同一行寫入多個語句時, 需要使用分號將他們分隔開;
- 在一行的末尾是可以繼續的語句時, 需要使用分號來明確終止該語句 .
// 分號用于分隔多個語句val x = 1 ; val y = 2// 分號用于終止可以繼續的語句if (x == 1) {println("x == 1") ; println("繼續執行")}
3- 塊表達式和賦值
在Scala中, 塊表達式 (Block Expressions) 是由一對花括號 {}
包圍的一系列表達式組成的結構;
在塊表達式中, 最后一個表達式的值即為整個塊表達式的值;
塊表達式可以用于包含多個操作或計算步驟, 并且可以隱藏中間變量, 使代碼更加清晰和簡潔;
在塊表達式中進行賦值時, 需要注意Scala中賦值語句的特性;
在Scala中, 賦值語句本身沒有返回值, 或者嚴格來說, 其返回值為 Unit
類型 (類似于java中的void
類型);
因此, 如果一個塊表達式以賦值語句結尾, 整個表達式的值將為 Unit
類型 ;
val x = 10val y = {val a = x + 5val b = a * 2b}println(y) // 輸出: 30val result = {var a = 5a += 1}println(result) // 輸出: ()
4- 輸入和輸出
使用 print 或者 println 打印一個值;
使用 printf 格式化輸出;
使用 readLine
從控制臺讀取一行輸入, 如果是讀取數字, Boolean 或者字符串, 可以使用 readInt
, readDouble
, readByte
, readShort
, readLong
, readFloat
, readBoolean
或者 readChar
;
與其它方法不同, readLine
帶一個參數作為提示字符串;
println("請輸入文本:")val input = StdIn.readLine()println("你輸入的文本是: " + input)
請輸入文本:
KFC
你輸入的文本是: KFC
5- 循環
Scala支持 while 循環和 for 循環, while 循環與java的 while 一樣, for 循環語法如下:
for(i <- 表達式)
遍歷字符串和數組時, 你通常需要使用 0 到 n-1 的區間, 這個時候可以使用 until 方法而不是 to 方法;
until 方法返回一個并不包含上限的區間;
for (i <- 1 to 10) { // 包含10, 1 - 10println(i)}
// 或者for (x <- 1 until 10) { // 不包含 10, 1 - 9println(x)}
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
6- 高級for循環和for推到式
可以使用變量 <-
表達式的形式提供多個生成器, 用分號隔開. 例如:
for(i <- 1 to 3; j <- 1 to 3)println(10 * i + j)
11
12
13
21
22
23
31
32
33
每個生成器還可以帶過濾條件, 以 if
開頭的 Boolean
表達式;
for(i <- 1 to 3; j <- 1 to 3 if i != j)println(10 * i + j)
12
13
21
23
31
32
如果 for
循環的循環體以 yield
開始, 則該循環會構造出一個集合, 每次迭代出集合中的一個值:
val list = for (i <- 1 to 10) yield i % 3println(list)
Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
這類循環叫做 for
推導式;
7- 函數
在Scala中, 函數是一等公民, 可以像變量一樣被傳遞、賦值和使用;
Scala中的函數可以具有參數、返回值, 并且可以嵌套定義;
函數可以被定義為匿名函數(lambda表達式), 也可以被命名并在其它地方調用;
要定義函數, 需要給出函數的名稱, 參數和函數體:
def abs(x:Double) = if (x>0) x else -x
必須給出所有參數的類型, 不過, 只要函數不是遞歸的, 就不需要指定返回類型;
Scala編譯器可以通過=
左右兩側的表達式推斷出返回類型;
如果函數體需要多個表達式完成, 可以使用代碼塊, 塊中最后一個表達式的值就是函數的返回值.
對于遞歸函數, 必須指定返回類型;
def abs(x: Double) = if (x>0) x else -x
// 調用函數
println(abs(2.12)) // 2.12
println(abs(-3)) // 3.0
8- 默認參數和帶名參數
在Scala中, 可以使用帶名參數和默認參數來提高代碼的可以讀性和靈活性;
帶名參數允許在調用函數時指定參數的名稱, 而不必按照函數定義的順序傳遞參數;
默認參數允許在定義函數時為參數指定默認值, 如果調用函數時未提供該參數的值, 則會使用默認值;
示例:
// 定義一個函數, 帶有默認值參數和帶名參數
def greet(name: String = "Horld", greeting: String = "Hello"): Unit = {println(s"$greeting, $name!")
}// 調用函數,使用默認參數
greet() // 輸出: Hello, World!
// 調用函數,使用帶名參數
greet(greeting = "Hi", name = "Taerge") // 輸出: Hi, Taerge!
在上面的示例中, greet
函數定義了兩個帶有默認值的參數 name
和 greeting
, 在調用函數時, 可以使用默認參數, 也可以通過指定參數的名稱來傳遞參數值 .
9- 可變參數
在Scala中, 可變參數允許函數接受可變數量的參數;
這種特性使得函數可以接受任意數量的參數, 而不需要提前確定參數的數量;
可變參數在Scala中使用 *
來定義, 通常稱為可變參數, 變長參數和可變長度參數;
示例:
// todo: 定義一個函數, 接受可變參數的函數def sum(args: Int*): Int = {var result = 0for (arg <- args) {result += arg}result}// 調用函數, 傳遞不定量的參數println(sum(1, 2, 3)) // 輸出: 6println(sum(1, 2, 3, 4, 5)) // 輸出: 15
在上面的示例中, sum
函數接受一個或多個整數作為參數, 并計算他們的總和;
通過在參數類型后面加上*
, 函數就可以接受不定數量的參數;
在調用函數時, 可以傳遞任意數量的參數, 這些參數會被收集成一個序列;
使用可變參數可以使函數更加靈活, 適用于需要處理不定數量參數的情況 .
10- 過程
在Scala中, 不返回值的函數有一種特殊的表示法, 即定義為過程(Procedure) ;
過程是指函數體包含在花括號中, 但沒有等號=
來指定返回類型, 此時函數的返回類型被推斷為 Unit
;
過程在Scala中用于執行一些操作而不返回任何值;
示例:
// todo: 定義一個過程, 不返回任何值def printHello(): Unit = {println("Hello, World!")}// 調用過程printHello() // 輸出: Hello, World!
在上面示例中, printHello()
函數是一個過程, 它打印 “Hello, World!” 而不返回任何值;
過程在Scala中通常用于執行副作用操作, 如打印, 寫入文件等, 而不需要返回結果;
通過定義過程, 可以明確表明函數的目的是執行一些操作而不產生返回值, 這有助于代碼的可讀性和清晰性 .
11- 懶值
在Scala中, 懶值 (lazy val) 是一種延遲初始化的特性, 它允許變量在首次訪問時才進行初始化;
懶值的聲明使用 lazy
關鍵字, 這樣可以推遲變量的初始化, 直到第一次訪問該變量時才進行實際的計算或賦值;
示例:
// todo: 定義一個類class Person {// 聲明一個懶值lazy val age: Int = {println("lazy value age is called")22}}// 創建一個對象val person = new Person// 訪問懶值println(person.age) // 第一次訪問, 會初始化并輸出: lazy value age is called , 輸出: 22println("-------------") // 輸出: -------------println(person.age) // 第二次訪問, 不會重新初始化, 直接輸出: 22
在上面的示例中, age
被聲明為懶值, 只有在第一次訪問 age
時才會執行初始化代碼;
懶值通常用于延遲初始化開銷較大的變量, 以提高性能和資源利用率;
懶值在Scala中是一種常用的技術, 可以幫助優化程序性能和資源利用 .
12- 異常
在Scala中, 異常處理是通過 try
、catch
和 finally
來實現的;
Scala中的異常分為可檢查異常 (checked exception) 和不可檢查異常 (unchecked exception) ;
Scala不強制要求捕獲或聲明可檢查異常, 因此通常情況下, Scala中的異常處理更接近于 java中的不可檢查異常處理;
示例:
// todo: 異常try {// 可能會拋出異常的代碼val result = 1 / 0} catch {case e: Exception =>// 處理異常的代碼println("除0異常發生: " + e.getMessage) // 輸出: 除0異常發生: / by zero} finally {println("無論如何都會執行的代碼") // 輸出: 無論如何都會執行的代碼// 釋放資源的代碼println("釋放資源") // 輸出: 釋放資源}
在上面的示例中, try
塊包含可能會拋出異常的代碼, catch
塊用于捕獲特定類型的異常并處理, finally
塊中的代碼無論如何是否發生異常都會執行;
除了 try
、catch
和 finally
, Scala還提供了 throw
關鍵字用于拋出異常. 另外, Scala中也支持使用 match
表達式來處理異常, 使異常處理更加靈活;