這個程式碼研究室是「程式設計人員的 Kotlin 新手上路課程」的一部分。如果您按部就班完成程式碼研究室,就能充分體驗到本課程的價值。視您的知識多寡而定,您或許能略過某些部分。本課程適用於熟悉物件導向語言,且想學習 Kotlin 的程式設計師。
簡介
在本程式碼研究室中,您將學習 Kotlin 程式設計語言的基本概念,包括資料型別、運算子、變數、控制結構,以及可為空值和不可為空值的變數。本課程適用於熟悉物件導向語言,且想學習 Kotlin 的程式設計師。
本課程的設計目標是協助您累積知識,但各單元之間彼此半獨立,因此您可以略過熟悉的部分,不必建構單一範例應用程式。為將這些範例連結在一起,許多範例都使用水族館主題。如要查看完整的魚缸故事,請參閱 Udacity 的程式設計人員 Kotlin 新手上路課程。
必備知識
- 如何在 IntelliJ IDEA 中建立專案
- 如何在 IntelliJ IDEA 中開啟及執行 Kotlin 的 REPL (Read-Eval-Print Loop) 程式碼 (依序點選「Tools」>「Kotlin」>「Kotlin REPL」)
課程內容
- 如何使用 Kotlin 資料類型、運算子和變數
- 如何使用布林值和條件
- 可為空值和不可為空值的變數之間的差異
- Kotlin 中的陣列、清單和迴圈運作方式
學習內容
- 使用 Kotlin REPL 學習 Kotlin 基礎知識
在這項工作中,您將瞭解 Kotlin 程式設計語言中的運算子和型別。
步驟 1:探索數值運算子
- 開啟 IntelliJ IDEA (如果尚未開啟)。
- 如要開啟 Kotlin REPL,請依序選取「Tools」 >「Kotlin」 >「Kotlin REPL」。
與其他語言一樣,Kotlin 使用 +
、-
、*
和 /
分別代表加、減、乘和除。Kotlin 也支援不同的數字類型,例如 Int
、Long
、Double
和 Float
。
- 在 REPL 中輸入下列運算式。如要查看結果,請在輸入每個運算式後按下
Control+Enter
鍵 (在 Mac 上則為Command+Enter
鍵)。
1+1 ⇒ res8: kotlin.Int = 2 53-3 ⇒ res9: kotlin.Int = 50 50/10 ⇒ res10: kotlin.Int = 5 1.0/2.0 ⇒ res11: kotlin.Double = 0.5 2.0*3.5 ⇒ res12: kotlin.Double = 7.0
請注意,運算結果會保留運算元的型別,因此 1/2 = 0,但 1.0/2.0 = 0.5。
- 請嘗試使用整數和十進位數字的不同組合來建立運算式。
6*50 ⇒ res13: kotlin.Int = 300 6.0*50.0 ⇒ res14: kotlin.Double = 300.0 6.0*50 ⇒ res15: kotlin.Double = 300.0
- 呼叫數字的一些方法。Kotlin 會將數字保留為基本型別,但您可以在數字上呼叫方法,就像數字是物件一樣。
2.times(3) ⇒ res5: kotlin.Int = 6 3.5.plus(4) ⇒ res8: kotlin.Double = 7.5 2.4.div(2) ⇒ res9: kotlin.Double = 1.2
步驟 2:練習使用型別
Kotlin 不會在數字型別之間隱含轉換,因此您無法將 short 值直接指派給 long 變數,或將 Byte
指派給 Int
。這是因為程式中常見的錯誤來源是隱含數字轉換。您隨時可以透過轉換類型指派不同類型的值。
- 如要查看一些可能的轉換,請在 REPL 中定義
Int
類型的變數。
val i: Int = 6
- 建立新變數,然後輸入上述變數名稱,後面加上
.to
。
val b1 = i.to
IntelliJ IDEA 會顯示可能的完成項目清單。這項自動完成功能適用於任何型別的變數和物件。
- 從清單中選取
toByte()
,然後列印變數。
val b1 = i.toByte()
println(b1)
⇒ 6
- 為不同類型的變數指派
Byte
值。
val b2: Byte = 1 // OK, literals are checked statically
println(b2)
⇒ 1
val i1: Int = b2
⇒ error: type mismatch: inferred type is Byte but Int was expected
val i2: String = b2
⇒ error: type mismatch: inferred type is Byte but String was expected
val i3: Double = b2
⇒ error: type mismatch: inferred type is Byte but Double was expected
- 如果作業傳回錯誤,請改為投放到電視。
val i4: Int = b2.toInt() // OK!
println(i4)
⇒ 1
val i5: String = b2.toString()
println(i5)
⇒ 1
val i6: Double = b2.toDouble()
println(i6)
⇒ 1.0
- 為了讓長數字常數更易讀,Kotlin 允許您在數字中加入底線,方便您閱讀。請嘗試輸入其他數值常數。
val oneMillion = 1_000_000 val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010
步驟 3:瞭解變數類型的值
Kotlin 支援兩種類型的變數:可變更和不可變更。使用 val
時,您可以指派值一次。如果您嘗試重新指派其他值,就會收到錯誤訊息。使用 var
時,您可以指派值,之後也能透過程式變更該值。
- 使用
val
和var
定義變數,然後為變數指派新值。
var fish = 1
fish = 2
val aquarium = 1
aquarium = 2
⇒ error: val cannot be reassigned
您可以為 fish
指派值,然後指派新值,因為這是以 var
定義。嘗試為 aquarium
指派新值會產生錯誤,因為該值是以 val
定義。
當編譯器可從內容判斷類型時,系統會推斷您儲存在變數中的類型。您隨時可以使用半形冒號標記法,明確指定變數的型別。
- 定義一些變數,並明確指定型別。
var fish: Int = 12
var lakes: Double = 2.5
一旦您或編譯器指派了型別,就無法變更型別,否則會發生錯誤。
步驟 4:瞭解字串
Kotlin 中的字串與其他程式設計語言中的字串非常相似,使用 "
表示字串,使用 '
表示單一字元,並可使用 +
運算子串連字串。您可以將字串範本與值合併來建立字串範本;$
variable
名稱會替換為代表該值的文字。這就是所謂的「變數插補」。
- 建立字串範本。
val numberOfFish = 5
val numberOfPlants = 12
"I have $numberOfFish fish" + " and $numberOfPlants plants"
⇒ res20: kotlin.String = I have 5 fish and 12 plants
- 建立含有運算式的字串範本。如同其他語言,值可以是運算式的結果。使用大括號
{}
定義運算式。
"I have ${numberOfFish + numberOfPlants} fish and plants"
⇒ res21: kotlin.String = I have 17 fish and plants
在這項工作中,您將瞭解 Kotlin 程式設計語言中的布林值和檢查條件。與其他語言一樣,Kotlin 也有布林值和布林運算子,例如小於、等於、大於等等 (<
、==
、>
、!=
、<=
、>=
)。
- 編寫
if
/else
陳述式。
val numberOfFish = 50
val numberOfPlants = 23
if (numberOfFish > numberOfPlants) {
println("Good ratio!")
} else {
println("Unhealthy ratio")
}
⇒ Good ratio!
- 請嘗試在
if
陳述式中使用範圍。在 Kotlin 中,您測試的條件也可以使用範圍。
val fish = 50
if (fish in 1..100) {
println(fish)
}
⇒ 50
- 撰寫包含多個案例的
if
。如需更複雜的條件,請使用邏輯 AND&&
和邏輯 OR||
。與其他語言一樣,您可以使用else if
建立多個案例。
if (numberOfFish == 0) {
println("Empty tank")
} else if (numberOfFish < 40) {
println("Got fish!")
} else {
println("That's a lot of fish!")
}
⇒ That's a lot of fish!
- 試試
when
陳述式。在 Kotlin 中,您可以使用when
陳述式,以更簡潔的方式編寫一系列if
/else if
/else
陳述式,這類似於其他語言中的switch
陳述式。when
陳述式中的條件也可以使用範圍。
when (numberOfFish) {
0 -> println("Empty tank")
in 1..39 -> println("Got fish!")
else -> println("That's a lot of fish!")
}
⇒ That's a lot of fish!
在這項工作中,您將瞭解可為空值與不可為空值的變數。無關的程式設計錯誤是無數錯誤的根源。Kotlin 導入不可為空值的變數,以減少錯誤。
步驟 1:瞭解可空值性
根據預設,變數不能為 null
。
- 宣告
Int
並將null
指派給該項目。
var rocks: Int = null
⇒ error: null can not be a value of a non-null type Int
- 在型別後方使用問號運算子
?
,表示變數可為空值。宣告Int?
並將null
指派給該項目。
var marbles: Int? = null
如果資料類型較為複雜 (例如清單):
- 您可以允許清單的元素為空值。
- 您可以允許清單為空值,但如果清單不是空值,則其元素不得為空值。
- 您可以允許清單或元素為空值。
清單和其他複雜資料類型會在後續工作中介紹。
步驟 2:瞭解「?」和 ?: 運算子
您可以使用 ?
運算子測試 null
,省去編寫許多 if
/else
陳述式的麻煩。
- 以較長的方式編寫程式碼,檢查
fishFoodTreats
變數是否不是null
。然後遞減該變數。
var fishFoodTreats = 6
if (fishFoodTreats != null) {
fishFoodTreats = fishFoodTreats.dec()
}
- 現在來看看如何使用
?
運算子,以 Kotlin 方式編寫。
var fishFoodTreats = 6
fishFoodTreats = fishFoodTreats?.dec()
- 您也可以使用
?:
運算子串連空值測試。請參閱以下範例:
fishFoodTreats = fishFoodTreats?.dec() ?: 0
這是簡寫,代表「如果 fishFoodTreats
不是 null
,則遞減並使用該值;否則使用 ?:
後的值,也就是 0」。如果 fishFoodTreats
為 null
,系統會停止評估,且不會呼叫 dec()
方法。
空值指標的相關重點
如果您真的很喜歡 NullPointerExceptions
,Kotlin 可讓您保留這些項目。非空值斷言運算子 !!
(雙驚嘆號) 會將任何值轉換為非空值型別,如果值為 null
,則會擲回例外狀況。
val len = s!!.length // throws NullPointerException if s is null
在這項工作中,您將瞭解陣列和清單,以及在 Kotlin 程式設計語言中建立迴圈的不同方式。
步驟 1:製作清單
清單是 Kotlin 中的基本型別,與其他語言中的清單類似。
- 使用
listOf
宣告清單並列印出來。這份清單無法變更。
val school = listOf("mackerel", "trout", "halibut")
println(school)
⇒ [mackerel, trout, halibut]
- 使用
mutableListOf
宣告可變更的清單。移除項目。
val myList = mutableListOf("tuna", "salmon", "shark")
myList.remove("shark")
⇒ res36: kotlin.Boolean = true
如果 remove()
方法成功移除傳遞的項目,就會傳回 true
。
步驟 2:建立陣列
與其他語言一樣,Kotlin 也有陣列。與 Kotlin 中的清單不同 (有可變動和不可變動版本),Array
沒有可變動版本。建立陣列後,大小就會固定。您無法新增或移除元素,但可以複製到新陣列。
使用 val
和 var
的規則與陣列和清單相同。
- 使用
arrayOf
宣告字串陣列。使用java.util.Arrays.toString()
陣列公用程式列印出來。
val school = arrayOf("shark", "salmon", "minnow")
println(java.util.Arrays.toString(school))
⇒ [shark, salmon, minnow]
- 以
arrayOf
宣告的陣列不會與元素相關聯,因此您可以混合類型,這很有幫助。宣告具有不同型別的陣列。
val mix = arrayOf("fish", 2)
- 您也可以為所有元素宣告單一類型的陣列。使用
intArrayOf()
宣告整數陣列。其他型別的陣列也有對應的建構工具或例項函式。
val numbers = intArrayOf(1,2,3)
- 使用
+
運算子合併兩個陣列。
val numbers = intArrayOf(1,2,3)
val numbers3 = intArrayOf(4,5,6)
val foo2 = numbers3 + numbers
println(foo2[5])
=> 3
- 嘗試不同的巢狀陣列和清單組合。與其他語言一樣,您可以巢狀方式使用陣列和清單。也就是說,當您將陣列放入陣列中時,會得到陣列的陣列,而不是兩個陣列內容的扁平化陣列。陣列的元素也可以是清單,清單的元素也可以是陣列。
val numbers = intArrayOf(1, 2, 3)
val oceans = listOf("Atlantic", "Pacific")
val oddList = listOf(numbers, oceans, "salmon")
println(oddList)
⇒ [[I@89178b4, [Atlantic, Pacific], salmon]
第一個元素 numbers
是 Array
。如果您未使用陣列公用程式列印陣列,Kotlin 會列印位址,而不是陣列內容。
- Kotlin 的一項優點是,您可以使用程式碼初始化陣列,不必將陣列初始化為 0。請試試這個例句:
val array = Array (5) { it * 2 }
println(java.util.Arrays.toString(array))
⇒ [0, 2, 4, 6, 8]
初始化程式碼位於大括號之間,即 {}
。在程式碼中,it
是指陣列索引,從 0 開始。
步驟 3:製作循環
現在您已擁有清單和陣列,可以按照預期方式逐一處理元素。
- 建立陣列。使用
for
迴圈疊代陣列並列印元素。
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
print(element + " ")
}
⇒ shark salmon minnow
- 在 Kotlin 中,您可以同時對元素和索引進行迴圈。請試試這個例句:
for ((index, element) in school.withIndex()) {
println("Item at $index is $element\n")
}
⇒ Item at 0 is shark Item at 1 is salmon Item at 2 is minnow
- 請嘗試不同的步幅和範圍。您可以指定數字或字元的範圍 (依字母順序)。與其他語言一樣,您不必以 1 為步進值。你可以使用
downTo
倒轉。
for (i in 1..5) print(i)
⇒ 12345
for (i in 5 downTo 1) print(i)
⇒ 54321
for (i in 3..6 step 2) print(i)
⇒ 35
for (i in 'd'..'g') print (i)
⇒ defg
- 試用幾個迴圈。與其他語言一樣,Kotlin 也有
while
迴圈、do...while
迴圈,以及++
和--
運算子。Kotlin 也有repeat
迴圈。
var bubbles = 0
while (bubbles < 50) {
bubbles++
}
println("$bubbles bubbles in the water\n")
do {
bubbles--
} while (bubbles > 50)
println("$bubbles bubbles in the water\n")
repeat(2) {
println("A fish is swimming")
}
⇒ 50 bubbles in the water 49 bubbles in the water A fish is swimmingA fish is swimming
在運算子、清單和迴圈等基本概念方面,Kotlin 與其他語言非常相似,但仍有一些重要差異。
Kotlin 的下列功能可能與其他語言不同:
- Kotlin 型別無法隱含轉換,請使用轉型。
- 使用
val
宣告的變數只能指派一次。 - 根據預設,Kotlin 變數不可為空值。使用
?
將變數設為可為空值。 - 使用 Kotlin 時,您可以在
for
迴圈中同時遍歷陣列的索引和元素。
下列 Kotlin 程式設計建構函式與其他語言中的建構函式類似:
- 陣列和清單可以包含單一類型或混合類型。
- 陣列和清單可以巢狀結構呈現。
- 您可以使用
for
、while
、do
/while
和repeat
建立迴圈。 when
陳述式是 Kotlin 版本的switch
陳述式,但when
更具彈性。
Kotlin 說明文件
如要進一步瞭解本課程的任何主題,或遇到問題,請前往 https://kotlinlang.org。
Kotlin 教學課程
https://try.kotlinlang.org 網站提供豐富的教學課程 (稱為 Kotlin Koans)、網頁式解譯器,以及附有範例的完整參考文件。
Udacity 課程
如要查看這個主題的 Udacity 課程,請參閱「程式設計人員的 Kotlin 新手上路課程」。
IntelliJ IDEA
IntelliJ IDEA 的說明文件位於 JetBrains 網站。
本節列出的作業可由課程講師指派給學習本程式碼研究室的學員。講師可自由採取以下行動:
- 視需要指派作業。
- 告知學員如何繳交作業。
- 為作業評分。
講師可以視需求使用全部或部分建議內容,也可以自由指派任何其他合適的作業。
如果您是自行學習本程式碼研究室,不妨利用這些作業驗收學習成果。
回答問題
第 1 題
下列哪一項會宣告不可變更的字串清單?
▢ val school = arrayOf("shark", "salmon", "minnow")
▢ var school = arrayOf("shark", "salmon", "minnow")
▢ val school = listOf("shark", "salmon", "minnow")
▢ val school = mutableListOf("shark", "salmon", "minnow")
第 2 題
下列程式碼的輸出內容為何?for (i in 3..8 step 2) print(i)
▢ 345678
▢ 468
▢ 38
▢ 357
第 3 題
這個程式碼中的問號用途為何?var rocks: Int? = 3
▢ 變數 rocks
的類型不固定。
▢ 變數 rocks
可以設為空值。
▢ 變數 rocks
不得設為空值。
▢ 變數 rocks
不應立即初始化。
繼續下一個課程:
如要查看課程總覽,包括其他程式碼研究室的連結,請參閱「程式設計人員的 Kotlin 新手上路課程:歡迎參加本課程。」