這一節名為 “i_introduction(介紹)”,主要向我們展示了Kotlin的語法,特性,與JAVA的相似與不同。
在使用Kotlin-koans學習時,我們的練習都在src
目錄下,開啟後可以看到我們的練習,我們要做的就是根據提示完成練習,並執行test
目錄下對應的單元測試,如果單元測試報錯,說明沒有通過,若什麼都沒輸出,則說明完成了練習。
0. _0_Hello_World
先貼一下程式碼
package i_introduction._0_Hello_World
import util.TODO
import util.doc0
fun todoTask0(): Nothing = TODO(
"""
Task 0.
Read README.md to learn how to work with this project and check your solutions.
Using 'documentation =' below the task description you can open the related part of the online documentation.
Press 'Ctrl+Q'(Windows) or 'F1'(Mac OS) on 'doc0()' to call the "Quick Documentation" action;
"See also" section gives you a link.
You can see the shortcut for the "Quick Documentation" action used in your IntelliJ IDEA
by choosing "Help -> Find Action..." (in the top menu), and typing the action name ("Quick Documentation").
The shortcut in use will be written next to the action name.
Using 'references =' you can navigate to the code mentioned in the task description.
Let's start! Make the function 'task0' return "OK". Note that you can return expression directly.
""",
documentation = doc0(),
references = { task0(); "OK" }
)
fun task0(): String {
return todoTask0()
}複製程式碼
閱讀TODO中的內容,首先要求我們閱讀README.md
檔案,學習如何使用該專案,瞭解通過該專案能學到什麼,並給出了Hello_World練習的答案。然後是教我們使用線上文件,可以看到程式碼中有一個doc0()
函式,將游標移動到該函式位置,按下 'Ctrl + Q'(Mac OS按 'F1')可以開啟快速文件,這裡是Kotlin
的詳細文件,點選連結便可在瀏覽器中檢視。注意一定要將游標移動到該函式位置,只是將滑鼠懸停在函式上方是不行的。
接下來就是本練習的內容了,修改task0()
函式使其返回一個"OK"
fun task0(): String {
return todoTask0()
}複製程式碼
練習中所有todo
字首的函式都是為了說明練習內容和不讓編輯器報錯的,我們修改時不需要改動它們,不要呼叫就可以了。
開始練習
fun task0(): String {
return "OK"
}複製程式碼
完成,也可以這樣,省略函式體,直接給函式賦值
fun task0(): String = "OK"複製程式碼
還可以這樣,連返回值型別都省略
fun task0() = "OK"複製程式碼
然後開啟test
目錄,找到對應的單元測試,執行
不出意外我們將看到如下結果
這就說明我們用
Kotlin
說出了Hello World
,馬不停蹄地開始下一個專案吧。
1. _1_Java_To_Kotlin_Converter
該練習教我們使用把Java
程式碼轉為Kotlin
程式碼的工具,Intellj IDEA 自帶了這個工具,我們將JavaCode1.java
中的task1
方法複製到n01JavaToKotlinConverter.kt
中,直接覆蓋對應的task1
函式就好了
- 選擇 => 複製
- 貼上 => Yes
- 轉換就完成了
執行測試,通過
2. _2_Named_Arguments
在Kotlin
中,我們在呼叫方法或函式的時候,可以使用方法或函式中形參的名字傳參,也可以為形參設定預設值
如
fun bar(i: Int, s: String = "", b: Boolean = true) {}複製程式碼
可以看到函式bar()
中有三個形參i,s,b
,s
和b
都設定了預設值,所以呼叫的時候必須傳遞的引數就只有i
了
bar(1)複製程式碼
因為可以使用形參的名字傳參,我們在呼叫函式的時候就不用關心引數的順序了
bar(1, b = fasle)複製程式碼
好方便
練習要求我們使用庫函式joinToString
設定前字尾{
和}
,我們使用形參名傳值
fun task2(collection: Collection<Int>): String {
return collection.joinToString(postfix = "}",prefix = "{")
}複製程式碼
完成,引數順序打亂都沒問題
3. _3_Default_Arguments
使用引數預設值,修改foo
函式,實現Java
中需要過載才能實現的功能
fun foo(name: String, number: Number = 42, toUpperCase: Boolean = false): String {
return (if (toUpperCase) name.toUpperCase() else name) + number
}
fun task3(): String {
return (foo("a") +
foo("b", number = 1) +
foo("c", toUpperCase = true) +
foo(name = "d", number = 2, toUpperCase = true))
}複製程式碼
完成,太方便了。
這裡我們注意到,Kotlin
中的if語句可以直接返回結果,不需要寫return
語句,而我們熟悉的三目運算子 ?:
在Kotlin
中另有它用。
4. _4_Lambdas
使用lambda表示式,遍歷集合,不能使用Iterables
,包含偶數返回ture
,反之false
fun task4(collection: Collection<Int>): Boolean = collection.any { x -> x % 2 == 0 }複製程式碼
呼叫Collection
的any
方法,並完成表示式即可,any
表示集合中有任一元素符合表示式,結果即為true
,我關於Lambda表示式的內容瞭解很少,還要專門學習。
5. _5_String_Templates
字串模板"Any expression can be used: ${if (c) x else y}"
,使用${}
可在字串中使用變數或表示式,用"""String"""
,字串中不需要用\
來轉義,可以直接使用各種符號,包括換行符
修改模板字串,使其可以匹配測試中的日期格式
fun task5(): String ="""\d{2}\ ${month}\ \d{4}"""複製程式碼
6. _6_Data_Classes
資料類,Kotlin
中專門用來構造資料實體類的方式,非常簡潔
補全Person
data class Person(val name: String, val age: Int)
7. _7_Nullable_Types
可空型別,練習要求我們重構JavaCode7.java
中的sendMessageToClient
方法,但是隻能使用一次if 語句,用Kotlin
當然是可以做到的
fun sendMessageToClient(client: Client?, message: String?, mailer: Mailer) {
if (client == null || message == null) return
val personalInfo = client.personalInfo ?: return
val email = personalInfo.email ?: return
mailer.sendMessage(email, message)
}複製程式碼
函式簽名中的跟在型別後邊的?表示可傳入空值,而在函式體中我們看到了已經不是原來的?:
的?:
,這裡的?:
稱為elvis
操作符,它的功能是判斷變數或表示式的值是否為空,非空返回操作符左邊,空則返回右邊,?:
是一個整體,不可在中間加入其他東西。
8. _8_Smart_Casts
使用智慧轉換和when
表示式完成eval方法,實現和JavaCode8.java
中同樣的功能
fun eval(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval(e.left) + eval(e.right)
else -> throw IllegalArgumentException("Unknown expression")
}複製程式碼
在Kotlin
中沒有switch
表示式,但是when
提供了更豐富的功能,在when
中,我們使用->
表示執行某一分支後的操作,->
之前是條件,條件不一定是某個值,它可以是任意表示式。
多個條件執行同一操作,可用,
分隔
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}複製程式碼
可以用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
智慧轉換型別,如同本練習
當when
沒有引數的時候,也可以用來替代if-else if
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}複製程式碼
還有,當編譯器認為我們提供的條件分支沒有覆蓋所以情況時,我們必須使用else
,它相當於switch
中的default
9. _9_Extension_Functions
Kotlin
支援為已經存在的類編寫擴充套件方法,而且不需要對原有類進行任何改動,只需要使用className.extensionFun
的形式就可以了
fun String.lastChar() = this.get(this.length - 1)複製程式碼
本練習要求我們使用擴充套件方法為Int
和Pair
擴充套件r
方法,r
方法的功能是構造一個RationalNumber
類的物件
fun Int.r(): RationalNumber = RationalNumber(this,1)
fun Pair<Int, Int>.r(): RationalNumber = RationalNumber(first,second)複製程式碼
簡單靈活,非常強大
10. _10_Object_Expressions
在JAVA
中我們要實現一個介面或使用一個抽象類時通常會使用匿名內部類,在Kotlin
中,我們使用Object Expressions
【物件表示式】,看上去這和在Java
中沒有太大不同
本練習中我們使用物件表示式來實現Collections.sort
中的Comparator
fun task10(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
Collections.sort(arrayList, object : Comparator<Int> {
override fun compare(o1: Int, o2: Int): Int = o2 - o1
})
return arrayList
}複製程式碼
11. _11_SAM_Conversions
Kotlin支援SAM轉換,我沒弄懂這是什麼原理,總之很神奇。使用這個功能,我們可以進一步簡化上一練習中的方法
fun task11(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
Collections.sort(arrayList, { x, y -> y-x })
return arrayList
}複製程式碼
12. _12_Extensions_On_Collections
Kotlin
的標準庫提供為Collections
提供了非常多有用的擴充套件方法,如上一練習當中的從大到小排序,方法名為sortedDescending
,呼叫此方法就可方便地完成排序了
fun task12(): List<Int> {
return arrayListOf(1, 5, 2).sortedDescending()
}複製程式碼