Kotlin快速入門(一)基礎
Kotlin快速入門(一)基礎
Kotlin學習筆記,主要記錄與Java不同的地方。
1 基本類型
1.1 數字
1)數字沒有隱式擴寬轉換
val b: Byte = 1 // OK, 字面值是靜態檢測的 val i: Int = b // 錯誤
但我們可以顯示轉換
val i: Int = b.toInt()
上下文推斷轉換類型是可以的
val l = 1L + 3 // Long + Int => Long
2)Kotlin中字符不是數字,但字符可以顯示轉換為數字
fun check(c: Char) { if (c == 1) { // 錯誤:類型不兼容 // …… } }
fun decimalDigitValue(c: Char): Int {if (c !in ‘0‘..‘9‘) throw IllegalArgumentException("Out of range") return c.toInt() - ‘0‘.toInt() // 顯式轉換為數字 }
3)可以使用下劃線使數字常量更易讀
val a=1_000_000
4)數字的封箱
val a: Int = 10000 print(a === a) // 輸出“true” val boxedA: Int? = a val anotherBoxedA: Int? = a print(boxedA === anotherBoxedA) // !!!輸出“false”!!!
val a: Int = 10000 print(a== a) // 輸出“true” val boxedA: Int? = a val anotherBoxedA: Int? = a print(boxedA == anotherBoxedA) // 輸出“true”
// 假想的代碼,實際上並不能編譯: val a: Int? = 1 // 一個裝箱的 Int (java.lang.Integer) val b: Long? = a // 隱式轉換產生一個裝箱的 Long (java.lang.Long) print(a == b) // 驚!這將打印 "false" 鑒於 Long 的 equals() 檢測其他部分也是 Long
1.2 運算
位運算列表(只用於 Int 和 Long ) :
shl(bits) – 有符號左移 (Java 的 << )
shr(bits) – 有符號右移 (Java 的 >> )
ushr(bits) – 無符號右移 (Java 的 >>> )
and(bits) – 位與
or(bits) – 位或
xor(bits) – 位異或
inv() – 位非
1.3 數組
數組在 Kotlin 中使用 Array 類來表示,它定義了 get 和 set 函數(按照運算符重載約定
這會轉變為 [] ) 和 size 屬性,以及一些其他有用的成員函數:
class Array<T> private constructor() { val size: Int operator fun get(index: Int): T operator fun set(index: Int, value: T): Unit operator fun iterator(): Iterator<T> // …… }
我們可以使用庫函數 arrayOf() 來創建一個數組並傳遞元素值給它,這樣 arrayOf(1, 2, 3)
創建了 array [1, 2, 3]。 或者,庫函數 arrayOfNulls() 可以用於創建一個指定大小、元素都
為空的數組。
另一個選項是用接受數組大小和一個函數參數的工廠函數,用作參數的函數能夠返回 給定索
引的每個元素初始值:
// 創建一個 Array<String> 初始化為 ["0", "1", "4", "9", "16"] val asc = Array(5, { i -> (i * i).toString() })
如上所述, [] 運算符代表調用成員函數 get() 和 set() 。
註意: 與 Java 不同的是,Kotlin 中數組是不型變的(invariant) 。這意味著 Kotlin 不讓我們把
Array<String> 賦值給 Array<Any> ,以防止可能的運行時失敗(但是你可以使用 Array<out
Any> , 參見類型投影) 。
Kotlin 也有無裝箱開銷的專門的類來表示原生類型數組: ByteArray 、
ShortArray 、 IntArray 等等。這些類和 Array 並沒有繼承關系,但是 它們有同樣的方法
屬性集。它們也都有相應的工廠方法:
val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
1.4 字符串
1)可以使用索引運算符訪問
如:s[i]
2)可以用 for 循環叠代字符串
for (c in str) { println(c) }
3)Kotlin 有兩種類型的字符串字面值: 轉義字符串可以有轉義字符,以及原生字符串可以包含換
行和任意文本。
轉移字符串(與Java類似)
val s = "Hello, world!\n"
原生字符串 使用三個引號(""" ) 分界符括起來,內部沒有轉義並且可以包含換行和任何其
他字符:
val text = """ for (c in "foo") print(c) """
4)字符串模板:
字符串可以包含模板表達式 ,即一些小段代碼,會求值並把結果合並到字符串中。 模板表達
式以美元符($ ) 開頭,由一個簡單的名字構成:
val i = 10 val s = "i = $i" // 求值結果為 "i = 10"
或者用花括號擴起來的任意表達式:
val s = "abc" val str = "$s.length is ${s.length}" // 求值結果為 "abc.length is 3"
原生字符串和轉義字符串內部都支持模板。 如果你需要在原生字符串中表示字面值 $ 字符
(它不支持反斜杠轉義) ,你可以用下列語法:
val price = """
${‘$‘}9.99
"""
二、包
如果出現名字沖突,可以使用 as 關鍵字在本地重命名沖突項來消歧義:
import foo.Bar // Bar 可訪問 import bar.Bar as bBar // bBar 代表“bar.Bar”
關鍵字 import 並不僅限於導入類;也可用它來導入其他聲明:
頂層函數及屬性
在對象聲明中聲明的函數和屬性;
枚舉常量
與 Java 不同,Kotlin 沒有單獨的 "import static" 語法; 所有這些聲明都用 import 關鍵字導
入 。
三、控制流
3.1 if表達式
在 Kotlin 中, if 是一個表達式,即它會返回一個值。 因此就不需要三元運算符(條件 ? 然
後 : 否則) ,因為普通的 if 就能勝任這個角色。
// 傳統用法 var max = a if (a < b) max = b // With else var max: Int if (a > b) { max = a } else { max = b } // 作為表達式 val max = if (a > b) a else b
if 的分支可以是代碼塊,最後的表達式作為該塊的值:
val max = if (a > b) { print("Choose a") a } else { print("Choose b") b }
如果你使用 if 作為表達式而不是語句(例如:返回它的值或者 把它賦給變量) ,該表達式
需要有 else 分支。
3.2 when表達式
when 取代了類 C 語言的 switch 操作符。
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> { // 註意這個塊 print("x is neither 1 nor 2") } }
when 既可以被當
做表達式使用也可以被當做語句使用。如果它被當做表達式, 符合條件的分支的值就是整個
表達式的值,如果當做語句使用, 則忽略個別分支的值。(像 if 一樣,每一個分支可以是
一個代碼塊,它的值 是塊中最後的表達式的值。)如果其他分支都不滿足條件將會求值 else 分支。 如果 when 作為一個表達式使用,則必須
有 else 分支, 除非編譯器能夠檢測出所有的可能情況都已經覆蓋了。
如果很多分支需要用相同的方式處理,則可以把多個分支條件放在一起,用逗號分隔:
when (x) { 0, 1 -> print("x == 0 or x == 1") else -> print("otherwise") }
我們可以用任意表達式(而不只是常量) 作為分支條件 :
when (x) { parseInt(s) -> print("s encodes x") else -> print("s does not encode x") }
也可以檢測一個值在(in ) 或者不在(!in ) 一個區間或者集合中 :
when (x) { in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above") }
檢測一個值是(is ) 或者不是(!is ) 一個特定類型的值。註意: 由於智
能轉換,你可以訪問該類型的方法和屬性而無需 任何額外的檢測 :
val hasPrefix = when(x) { is String -> x.startsWith("prefix") else -> false }
when 也可以用來取代 if - else if 鏈。 如果不提供參數,所有的分支條件都是簡單的布
爾表達式,而當一個分支的條件為真時則執行該分支:
3.3 for循環
for 循環可以對任何提供叠代器(iterator) 的對象進行遍歷,語法如下:
for (item in collection) print(item)
循環體可以是一個代碼塊:
for (item: Int in ints) { // …… }
如上所述, for 可以循環遍歷任何提供了叠代器的對象。即:
有一個成員函數或者擴展函數 iterator() ,它的返回類型
有一個成員函數或者擴展函數 next() ,並且
有一個成員函數或者擴展函數 hasNext() 返回 Boolean 。
這三個函數都需要標記為 operator 。
對數組的 for 循環會被編譯為並不創建叠代器的基於索引的循環。
如果你想要通過索引遍歷一個數組或者一個 list,你可以這麽做:
for (i in array.indices) { print(array[i]) }
註意這種“在區間上遍歷”會編譯成優化的實現而不會創建額外對象。
或者你可以用庫函數 withIndex :
for ((index, value) in array.withIndex()) { println("the element at $index is $value") }
3.4 while循環
同Java
四、返回和跳轉
1)Kotlin 有三種結構化跳轉表達式:
return 。默認從最直接包圍它的函數或者匿名函數返回。
break 。終止最直接包圍它的循環。
continue 。繼續下一次最直接包圍它的循環。
所有這些表達式都可以用作更大表達式的一部分:
val s = person.name ?: return
這些表達式的類型是 Nothing 類型。
2)我們可以用標簽限制 break 或者 continue
[email protected] for (i in 1..100) { for (j in 1..100) { if (……) break@loop } }
從lamada表達式返回
fun foo() { ints.forEach [email protected] { if (it == 0) return@lit print(it) } }
也可使用隱式標簽
fun foo() { ints.forEach { if (it == 0) return@forEach print(it) } }
用一個匿名函數替代 lambda 表達式。 匿名函數內部的 return 語句將從該匿名
函數自身返回
fun foo() { ints.forEach(fun(value: Int) { if (value == 0) return print(value) }) }
當要返一個回值的時候,解析器優先選用標簽限制的 return,即
return@a 1 //意為“從標簽 @a 返回 1”,而不是“返回一個標簽標註的表達式 (@a 1) ”。
Kotlin快速入門(一)基礎