程式設計人員 Kotlin 新手上路課程:Kotlin 基本概念

本程式碼研究室是程式設計課程 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:探索數字運算子

  1. 開啟 IntelliJ IDEA (如果尚未開啟)。
  2. 如要開啟 Kotlin REPL,請選取 [Tools] (工具) > [Kotlin] > [Kotlin REPL]

Kotlin 與其他語言的 Kotlin 一樣使用 +-*/。Kotlin 也支援不同的數字類型,例如 IntLongDoubleFloat

  1. 在 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。

  1. 請試試不同的整數和小數組合。
6*50
⇒ res13: kotlin.Int = 300

6.0*50.0
⇒ res14: kotlin.Double = 300.0

6.0*50
⇒ res15: kotlin.Double = 300.0
  1. 針對數字呼叫某些方法。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。這是因為隱含數字轉換是程式中常見的錯誤來源。您可以隨時使用投放功能指定不同類型的值。

  1. 如要查看一些投放,請在 REPL 中定義 Int 類型的變數。
val i: Int = 6
  1. 建立新變數,然後輸入上方出現的變數名稱,後面加上「.to」。
val b1 = i.to

IntelliJ IDEA 會顯示可能的完成清單。這個自動完成功能適用於任何類型的變數和物件。

  1. 從清單中選取 [toByte()],然後列印變數。
val b1 = i.toByte()
println(b1)
⇒ 6
  1. 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
  1. 如果是傳回錯誤的作業,請改為投放。
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
  1. 為方便您閱讀長篇數字常數,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 時,您可以指派一個值,稍後在計劃中變更該值。

  1. 請使用 valvar 定義變數,然後為它們指派新的值。
var fish = 1
fish = 2
val aquarium = 1
aquarium = 2
⇒ error: val cannot be reassigned

您可以為「fish」指派一個值,然後為其指派新的值,因為該值由 var 定義。為「aquarium」指派新的值時會發生錯誤,因為該值使用 val 定義。

當編譯器能夠根據結構定義找出特定變數時,系統就會推論您儲存在變數中的類型。如有需要,您可以隨時使用冒號標記明確指定變數類型。

  1. 請定義幾個變數並明確指定類型。
var fish: Int = 12
var lakes: Double = 2.5

您或編譯器指派類型後,您就無法變更類型,否則會收到錯誤訊息。

步驟 4:瞭解字串

在 Kotlin 中,字串的運作方式與任何其他程式設計語言中的字串類似,使用 " 代表字串,而 ' 則適用於單一字元,而您可以使用 + 運算子串連字串。建立字串範本時,您可將其與值結合;$variable 名稱則會替換成代表值的文字。這就是所謂的變數內插

  1. 建立字串範本。
val numberOfFish = 5
val numberOfPlants = 12
"I have $numberOfFish fish" + " and $numberOfPlants plants"
⇒ res20: kotlin.String = I have 5 fish and 12 plants
  1. 建立含有範本的字串範本。如同其他語言,值可以是運算式的結果。請使用大括號 {} 定義運算式。
"I have ${numberOfFish + numberOfPlants} fish and plants"
⇒ res21: kotlin.String = I have 17 fish and plants

在這項工作中,您將會瞭解到關於 Kotlin 程式設計語言的布林值和檢查條件。Kotlin 和其他語言一樣,具有布林和布林運算子,例如小於、等於、大於等 (<==>!=<=>=)。

  1. 撰寫 if/else 陳述式。
val numberOfFish = 50
val numberOfPlants = 23
if (numberOfFish > numberOfPlants) {
    println("Good ratio!") 
} else {
    println("Unhealthy ratio")
}
⇒ Good ratio!
  1. 請嘗試使用 if 陳述式的範圍。在 Kotlin 中,測試的條件也可以使用範圍。
val fish = 50
if (fish in 1..100) {
    println(fish)
}
⇒ 50
  1. 編寫包含多個案例的 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!
  1. 試用 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

  1. 宣告 Int 並指派 null
var rocks: Int = null
⇒ error: null can not be a value of a non-null type Int
  1. 在類型後方使用問號運算子 ?,表示變數可以是空值。宣告 Int? 並指派 null
var marbles: Int? = null

如果有複雜的資料類型 (例如清單):

  • 您可以允許清單元素為空值。
  • 您可以允許清單是 null,如果 是 null,其元素不能是 null。
  • 您可以允許清單或元素為空值。

後續部分工作會涵蓋清單和其他一些複雜的資料類型。

步驟 2:瞭解 ?和 ?: 運算子

你可以透過 ? 運算子測試 null,省去編寫 if / else 陳述式的麻煩。

  1. 請撰寫一些程式碼來檢查 fishFoodTreats 變數是否為 null。然後降低該變數。
var fishFoodTreats = 6
if (fishFoodTreats != null) {
    fishFoodTreats = fishFoodTreats.dec()
}
  1. 現在,透過 ? 運算子查看 Kotlin 編寫方法的方式。
var fishFoodTreats = 6
fishFoodTreats = fishFoodTreats?.dec()
  1. 您還可以使用 ?: 運算子連結空值。請參考下列範例:
fishFoodTreats = fishFoodTreats?.dec() ?: 0

fishFoodTreats」並非「null」,但並非採用「null」,請予以拒絕;否則,請使用 ?: 之後的值,也就是 0。如果 fishFoodTreatsnull,則系統會停止評估作業,且不會呼叫 dec() 方法。

關於空值指標的點

如果你真的很喜歡 NullPointerExceptions,Kotlin 也能讓你保有。非空值的宣告運算子 !! (雙精度值) 會將任何值轉換為非空值類型,並在值為 null 時擲回例外狀況。

val len = s!!.length   // throws NullPointerException if s is null

在這項工作中,您可以瞭解陣列和清單,並瞭解使用 Kotlin 程式設計語言建立迴圈的不同方法。

步驟 1:建立清單

清單是 Kotlin 中的基礎類型,與其他語言的清單類似。

  1. 使用 listOf 宣告清單並列印清單。這份清單無法變更。
val school = listOf("mackerel", "trout", "halibut")
println(school)
⇒ [mackerel, trout, halibut]
  1. 宣告可使用 mutableListOf 變更的清單。移除項目。
val myList = mutableListOf("tuna", "salmon", "shark")
myList.remove("shark")
⇒ res36: kotlin.Boolean = true

remove() 方法會在成功移除傳送的項目時傳回 true

步驟 2:建立陣列

Kotlin 和其他語言一樣,都有陣列。不同於 Kotlin 中的清單 (可變動且不可變更的版本),Array 沒有可變動的版本。建立陣列後,該大小即告固定。除非您複製到新陣列,否則無法新增或移除元素。

使用 valvar 的規則與陣列和清單相同。

  1. 使用 arrayOf 宣告字串陣列。請使用 java.util.Arrays.toString() 陣列公用程式進行列印。
val school = arrayOf("shark", "salmon", "minnow")
println(java.util.Arrays.toString(school))
⇒ [shark, salmon, minnow]
  1. 使用 arrayOf 宣告的陣列沒有與該元素相關聯的類型,因此您可以混用類型,這很有幫助。宣告各種類型的陣列。
val mix = arrayOf("fish", 2)
  1. 您也可以針對所有元素宣告一種類型的陣列。使用 intArrayOf() 宣告整數陣列。其他類型陣列都有對應的建構工具 (或執行個體化函式)。
val numbers = intArrayOf(1,2,3)
  1. 結合 + 陣列與兩個陣列。
val numbers = intArrayOf(1,2,3)
val numbers3 = intArrayOf(4,5,6)
val foo2 = numbers3 + numbers
println(foo2[5])
=> 3
  1. 嘗試不同的巢狀陣列和清單組合。如同其他語言,您還可以建立陣列與清單的巢狀結構。也就是說,將陣列置入陣列中,有一個陣列陣列,而不是兩個 的平面的平面陣列。陣列元素也可以是清單,清單元素可以是陣列。
val numbers = intArrayOf(1, 2, 3)
val oceans = listOf("Atlantic", "Pacific")
val oddList = listOf(numbers, oceans, "salmon")
println(oddList)
⇒ [[I@89178b4, [Atlantic, Pacific], salmon]

第一個元素 numbersArray。當您不使用陣列公用程式來列印時,Kotlin 會列印地址,而非陣列的內容。

  1. Kotlin 的其中一項優點是,您可以使用程式碼初始化陣列,而不是將其初始化為 0。請試試下列範例:
val array = Array (5) { it * 2 }
println(java.util.Arrays.toString(array))
⇒ [0, 2, 4, 6, 8]

初始化程式碼位於大括號 {} 之間。在程式碼中,it 代表陣列索引,開頭為 0。

步驟 3:建立迴圈

現在已經有清單和陣列了,讓元素循環播放可正常運作。

  1. 建立陣列。使用 for 迴圈疊代陣列並列印元素。
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
    print(element + " ")
}
⇒ shark salmon minnow
  1. 在 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. 請嘗試不同的步驟大小和範圍。您可以指定字母或數字範圍的字元範圍。如同其他語言,您就不需要向前邁進 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
  1. 試試循環播放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 程式設計結構與其他語言的類似,如下所示:

  • 陣列和清單可以有一種類型,也可以混合使用。
  • 陣列和清單可以是巢狀結構。
  • 您可以使用 forwhiledo/whilerepeat 建立迴圈。
  • 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 不應立即初始化。

繼續下一堂課:3. 函式

如需課程簡介,包括其他程式碼研究室的連結,請參閱程式設計人員 Kotlin 新手課程:歡迎參加這堂課程。