本程式碼研究室是程式設計課程 Kotlin 新手上路課程的一部分。使用程式碼研究室逐步完成程式碼課程後,您將能充分發揮本課程的潛能。視您的知識而定,您或許可以略過某些部分。本課程的適用對象為熟悉物件導向語言,且想要學習 Kotlin 的程式設計人員。
簡介
在這個程式碼研究室中,您將瞭解 Kotlin 程式設計語言的基本概念:資料類型、運算子、變數、控制結構,以及空值與非空值變數。本課程的適用對象為熟悉物件導向語言並想學習 Kotlin 的程式設計人員。
本課程並非只建立一個範例應用程式,而是用來建立您的知識,但彼此之間互不相關,因此您可以熟悉自己熟悉的部分。許多產品是透過水族箱主題進行連結。如果您想看完整的水族箱故事,請參考程式設計程式 Kotlin 新手上路課程。
須知事項
- 如何在 IntelliJ IDEA 中建立專案
- 如何在 IntelliJ IDEA 中透過 Kotlin's 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 一樣使用 +
、-
、*
和 /
。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 不會以隱含方式在數字類型之間轉換,因此您可以將短值直接指派給長變數,或是將 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
。若需更複雜的條件,請使用邏輯和&&
,以及邏輯或||
。與其他語言版本相同,您可以透過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
陳述式。不妨使用when
陳述式 (例如其他語言的switch
陳述式),以 Kotlin 編寫一系列的if
/else if
/else
陳述式。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
如果有複雜的資料類型 (例如清單):
- 您可以允許清單元素為空值。
- 您可以允許清單是 null,如果 是 null,其元素不能是 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
」,但並非採用「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
可設為 null。
▢ 變數 rocks
不得設為空值。
▢ 變數 rocks
不應立即初始化。
繼續下一堂課:
如需課程簡介,包括其他程式碼研究室的連結,請參閱程式設計人員 Kotlin 新手課程:歡迎參加這堂課程。