Scala/基本型別
Scala 是一種靜態型別的語言。這意味著當 Scala 程式被編譯時,編譯器會驗證對物件的運算是否根據它們的型別有效,如果不是,就會給出關於型別錯誤的資訊。一個簡單的例子,由於型別錯誤而被拒絕的程式
println(" " * 4.5) //ERROR: Required "Int" but found "Double".
字串方法 "*" 未為實數定義,因此當編譯器編譯程式時,它無法找到任何版本在字串上使用實數作為引數的 "*" 方法,因此它輸出一條錯誤資訊。錯誤資訊取決於編譯器及其版本,但通常包括位置、特定型別錯誤和其他有用資訊。
透過給出整數值來修復程式,我們得到以下程式
println(" " * 4) //Prints " ".
由於字串方法 "*" 為整數定義,因此編譯器會驗證型別是否有效,並接受程式。
可以使用型別註解來指示值、變數和表示式的型別
val someInteger = 3:Int
val someReal = 4:Double
//val someString = 5:String //ERROR: Required "String" but found "Int".
在第一行中,我們宣告一個名為 "someInteger" 的值,它被賦予表示式 "3:Int"。冒號後跟著 "Int" 是一個型別註解,指定 3 是 "Int" 型別。編譯器在型別檢查期間會驗證這是否有效。在第二行中,我們宣告一個名為 "someReal" 的值,它被賦予表示式 "4:Double"。雖然 "4" 通常被解釋為 "Int",但型別註解意味著它被解釋為 "Double"。在第三行中,我們宣告一個名為 "someString" 的值,它被賦予表示式 "5:String"。但是,"5" 不能被解釋為 "String",型別檢查會失敗,並從編譯器收到錯誤資訊。
在上面的例子中,"3" 的型別註解不是嚴格要求的。型別註解通常是可選的,可以放置在多個地方
val someInt = 4 + 6
val someInt2:Int = 4 + 6
val someInt3 = (4 + 6):Int
val someInt4:Int = (4 + 6):Int
val someInt5:Int = (4 + 6:Int):Int
型別註解通常不需要的原因是 Scala 支援型別推斷,這意味著它通常可以根據不同的元素推斷出型別。型別註解可以作為型別推斷器的指南,例如,當它難以推斷型別時,或者當它推斷出錯誤的型別時。
需要型別註解的例子包括函式定義的引數和遞迴函式的返回值型別。
"Boolean" 只有兩個可能的值:true 和 false。關鍵字 "true" 和 "false" 是 "Boolean" 的字面量
val thisIsTrue = true
val thisIsFalse = false
布林值上有幾個運算子。最常見的單目運算子是補碼或否定,在 Scala 中由 "!" 方法實現
println(!true) //Prints "false".
println(!false) //Prints "true".
兩個最常見的二元運算子是合取,或 "and",和析取,或 "inclusive or"。在 Scala 中,合取和析取分別由 "&&" 和 "||" 方法實現
println(true && true) //Prints "true".
println(true && false) //Prints "false".
println(false && true) //Prints "false".
println(false && false) //Prints "false".
println(true || true) //Prints "true".
println(true || false) //Prints "true".
println(false || true) //Prints "true".
println(false || false) //Prints "false".
其他二元運算子包括等於(由 "==" 實現)、不等於(由 "!=" 實現)和異或(由 "^" 實現)。
布林型通常用於決策。一個簡單的例子是 if-then-else 表示式,它使用 Boolean 型別的表示式來決定哪個分支需要計算
val result = if (true && (false || true) && !false) 3 else 5
println(result) //Prints "3".
整數型別描述了離散的數字,即它們沒有任何分數。不同的整數型別在它們可以表示的數字範圍上有所不同。它們包括 "Byte"、"Short"、"Int"、"Long"、"BigInt" 和 "Char"。下表描述了每種型別可以表示的離散數字的範圍
| 型別 | 最小數字 | 最大數字 |
|---|---|---|
| Byte | -27 | 27 - 1 |
| Short | -215 | 215 - 1 |
| Int | -231 | 231 - 1 |
| Long | -263 | 263 - 1 |
| BigInt | -無窮大 | 無窮大 |
| Char | 0 | 216 - 1 |
"Byte"、"Short"、"Int" 和 "Long" 用於表示數字或資料。它們支援簡單的算術運算子,例如否定、加法、減法、乘法、除法和模運算
println(-2) //Prints "-2".
println(2 + 5) //Prints "7".
println(2 - 5) //Prints "-3".
println(2 * 5) //Prints "10".
println(2 / 5) //Prints "0".
println(2 % 5) //Prints "2".
println(-(2:Byte)) //Prints "-2".
println((2:Short) + (5:Int)) //Prints "7".
println((2:Byte) - (5:Long)) //Prints "-3".
注意,涉及 "Byte"、"Short" 和 "Int" 但不涉及 "Long" 的算術運算將轉換為 "Int",而涉及 "Long" 和任何其他型別的運算將轉換為 "Long"。模運算可以給出負值,除法和模運算的設計使得等式 "b * (a/b) + (a%b) == a" 通常成立,即使對於負 "a" 和 "b" 也成立。除法或模運算的第二個引數不能為 0
//println(3 / 0) //ERROR: Throws an arithmetic exception.
//println(3 % 0) //ERROR: Throws an arithmetic exception.
也支援關係運算符,例如小於、小於或等於、等於和不等於
println(3 < 5) //Prints "true".
println(3 <= 5) //Prints "true".
println(3 == 5) //Prints "false".
println(3 != 5) //Prints "true".
其他關係運算符包括大於和大於或等於,它們分別由 ">" 和 ">=" 實現。
位運算子包括 "~"、"&"、"|" 和 "^",位移運算子包括 "<<"、">>" 和 ">>>"。
字面量可以透過寫出數字來宣告。替代表示法包括八進位制和十六進位制
println(10) //Prints "10".
println(010) //Prints "8".
println(0x10) //Prints "16".
println(0X10) //Prints "16".
在第一行中,列印 "10"。在第二行中,我們透過在數字前加上 "0" 來寫八進位制數 "10",並列印 "8",這是相應的十進位制數。在第三行中,我們透過在數字前加上 "0x" 來寫十六進位制數 "10",並列印 "16",這是相應的十六進位制數。第四行與第三行類似,只是使用 "0X" 而不是 "0x" 來進行字首。請注意,數字總是以十進位制表示法列印。
除了字首 "0x" 或 "0X" 之外,十六進位制字面量還包含普通數字以及字母 "a" 到 "f"。小寫和大寫之間沒有區別
println(0xff) //Prints "255".
println(0xFF) //Prints "255".
println(0xA0) //Prints "160".
println(0x10aB) //Prints "4267".
"Long" 字面量透過在數字後面新增 "l" 或 "L" 來表示
println(100l) //Prints "100".
println(077L) //Prints "63".
println(0xFFL) //Prints "255".
//println(2147483648) //ERROR: integer number is too large.
println(2147483648L) //Prints "2147483648".
整數溢位和下溢是當在某個整數表示式中,計算出的數字對於整數型別來說太大或太小而無法容納時發生的
println(2147483647) //Prints "2147483647".
println(2147483647 + 1) //Prints "-2147483648".
println(-2147483648 - 1) //Prints "2147483647".
在第一行中,列印了 "Int" 的最大數字。在第二行中,列印了 "Int" 的最大數字加 1,錯誤地給出了 "Int" 的最小數字。在第三行中,列印了 "Int" 的最小數字減 1,錯誤地給出了 "Int" 的最大數字。下溢和溢位通常不會引起異常,但會導致錯誤的結果。
避免溢位和下溢的常規做法是確保使用的整數型別始終足夠大以容納表示式。這必須在計算的每一步都完成
val wrongResult:Long = 24 * 60 * 60 * 1000 * 1000
println(wrongResult) //Prints "500654080".
val rightResult:Long = 24L * 60 * 60 * 1000 * 1000
println(rightResult) //Prints "86400000000".
在第一行中,表示式中的整數字面量被解釋為 "Int"。因為 "Int" 不足以包含所有中間結果,所以會發生溢位,並給出錯誤的結果。在錯誤的結果計算出來後,它被轉換為 "Long" 並存儲在值 "wrongResult" 中。在第二行中,列印 "wrongResult",給出錯誤的數字 "500654080"。在第三行中,第一個整數字面量被指示為 "Long" 型別。由於運算子是左結合的,並且涉及 "Int" 和 "Long" 的表示式具有 "Long" 型別,所以中間結果的型別為 "Long",並且足夠大以容納結果數字,而不會發生溢位。結果被儲存在值 "rightResult" 中。在第四行中,列印 "rightResult",給出正確的數字 "86400000000"。
BigInt 支援任意精度,這意味著它可以表示所有離散數字,只要有足夠的記憶體可用
//val someNum = 100000000000000000000L //ERROR: integer number is too large.
val someNum = BigInt("100000000000000000000")
println(someNum) //Prints "100000000000000000000".
println(someNum + someNum * 2) //Prints "300000000000000000000".
在第一行,我們嘗試使用“Long”字面量宣告一個數字,但該數字太大而無法儲存在“Long”中,編譯器會報錯。在第二行,我們使用字串聲明瞭相同的數字,並將其分配給“someNum”值。在第三行,我們列印“someNum”的值。在第四行,我們對someNum和一個“Int”型別的整數字面量進行基本運算,並列印結果。
“BigInt”的運算和記憶體使用取決於它所表示的數字的大小,通常比其他整數型別慢。由於它具有任意精度,因此純粹使用“BigInt”進行的計算永遠不會導致整數溢位或下溢。
“Char”首先用於表示字串中的字元。
待辦事項:擴充套件此部分。
待辦事項:寫一些關於“Unit”,“Any”,“Nothing”等內容。也許還有“null”。待辦事項:討論結合律。