kotlin學習之Kotlin Koans練習

學習資源

Kotlin Koans:Kotlin 在線練習題,適合有一定基礎的Kotlin學習者。
簡單介紹下該如何去做練習,鏈接中左邊爲練習的目錄,中間爲代碼編輯器,右邊爲這道練習題的介紹。建議在做之前去點一下介紹中高亮的鏈接,有助於理解。同時博主是一邊看《Kotlin in Action》一邊練習的,所以這邊給出每章讀完適宜去做哪幾個練習,在給予練習答案的同時,一併講解所涉及的知識點。
在這裏插入圖片描述

2 kotlin基礎

學完第二章後,大概掌握了函數和變量,類和屬性,字符串,when表達式,職能轉換,for循環,迭代區間,in等知識,適宜去做接下來幾個練習。

Hello, world!

本題的目的是讓我們寫一個start函數,並返回字符串"OK"。
在這裏插入圖片描述
我們點開鏈接,有如下四行代碼:
1.一個具有兩個Int輸入參數和Int返回參數的函數。

fun sum(a: Int, b: Int): Int {
    return a + b
}

2.方法可以以表達式形式,由編譯器推斷出應該返回的類型。

fun sum(a: Int, b: Int) = a + b

3.方法也可以沒有返回值(使用Unit)

fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}
//結果
sum of -1 and 8 is 7

4.Unit也可以忽略

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

看完鏈接就知道該怎麼在todo處填寫代碼了

fun start(): String = "OK"

成功後會顯示:Passed:testOK。實在想不出來也可以點擊Revert按鈕右邊的show answer按鈕。

Data classes

在這裏插入圖片描述
簡單來說,就是讓我們寫一個類,以實現右邊代碼中的功能。
我們使用數據類,相比於java中要寫get和set函數,而在kotlin中不需要寫這些函數。屬性可以是隻讀屬性(val)和可寫屬性(var),只讀屬性有一個getter,可寫屬性既有getter和setter。

data class Person(val name: String,var age: Int)

當我們調用Person實例的age屬性,相當於是java中調用get函數,而我們更改其值時又相當於調用set函數。

val person = Person("Bob",15)
println(person.age)
person.age = 20
println(person.age)

我們也可以自定義訪問器。

data class NewPerson(val name: String,val age: Int)
{
    val isOld:Boolean
    	get(){
        return age>50
    }
}
fun main(args:Array<String>)
{
    val person1 = NewPerson("liu",51)
    val person2 = NewPerson("zhang",20)
    println(person1.isOld)
    println(person2.isOld)
}

接下來我們看看鏈接說了什麼。
編譯器除了get和set還幫我們實現了以下方法。(toString能顯示出如下前提是data class)
在這裏插入圖片描述
同時,注意,編譯器只使用在主構造函數中爲自動生成的函數定義的屬性。要從生成的實現中排除屬性,請在類主體中聲明它。繼續看剛剛的例子。我們在Newperson類中又定義了一個新的屬性sex。

data class NewPerson(val name: String,val age: Int)
{
    var sex: Int = 0
    val isOld:Boolean
    	get(){
        return age>50
    }
}
fun main(args:Array<String>)
{
    val person1 = NewPerson("liu",51)
    val person2 = NewPerson("liu",51)
     println(person1.equals(person2))
    person2.sex = 1
    println(person1.equals(person2))
    println(person2)
}

我們在main函數中定義了兩個變量,他們的name屬性與age屬性相同,判斷二者是否相同,之後將person2的sex屬性設置爲1,繼續判斷是否相同,最後輸出person2,我們看結果。可以看到只有在類主體中聲明的屬性纔會被用來使用(toString(), equals(), hashCode(), copy())。

true
true
NewPerson(name=liu, age=51)

回到練習,答案現在很清晰了。

data class Person(val name: String,val age: Int)

Smart casts

在這裏插入圖片描述
這個練習和2.3.5中的小例子是一模一樣的,所以這裏就整理下涉及到的知識點。
1.智能轉換
首先,在kotlin中,要是用is檢查來判斷一個變量是否是某種類型,和java中的instanceOf相似,不過java中判斷之後,還需要進行類型轉換,比如當前對象expr是Num類型,在java中還要將expr轉換成Num,纔可以調用Num的方法或屬性。在kotlin中,如果你檢查過一個變量是某種類型,後面就不需要再轉換它,可以把它當做你檢查過的類型使用,這種轉換方式就叫智能轉換
2.when的用法
when是一個有返回值的表達式,因此可以寫一個直接返回when表達式的表達式體函數。

enum class Color{
    Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
fun getColor(color: Color)=when(color){
        Color.Red -> "Richard"
        Color.Orange -> "Of"
        Color.Yellow -> "York"
        Color.Green -> "Gave"
        Color.Blue -> "Battle"
        Color.Indigo -> "In"
        Color.Violet -> "Vain"
    }

和java不同,不需要在每個分支都寫上break語句。也可以把多個值合併到同一個分支,只需要用逗號隔開這些值。

Color.Red, Color.red -> "Richard"

when結構比switch更強大的點在於,switch要求必須使用常量(枚舉常量,字符串或者數字字面值)作爲分支條件,而when允許使用任何對象。setOf函數可以創建出一個Set,它會包含所有指定爲函數實參的對象when表達式把它的實參依次和所有分支匹配,直到某個分支滿足條件。這裏setOf(c1,c2)被用來檢查是否和分支條件相等:先和setOf(Red,Yellow)比較,然後是其他顏色的set,一個接一個。如果沒有其他的分支滿足條件,else分支會執行。

//when中的子分支條件可以是任何對象。而switch中必須是常量
fun  mix(c1: Color,c2: Color) = 
	when(setOf(c1,c2)){
    	setOf(Color.Red,Color.Yellow) -> Color.Orange
    	setOf(Color.Yellow,Color.Blue) -> Color.Green
        setOf(Color.Blue,Color.Violet) -> Color.Indigo
        else -> throw Exception("Dirty color")
}
fun main(arg: Array<String>){
    //println(getColor(Color.Orange))
    println(mix(Color.Yellow,Color.Red))
    println(mix(Color.Yellow,Color.Yellow))
}
//輸出
Orange
Exception in thread "main" java.lang.Exception: Dirty color
    at Test2_3Kt.mix(test2_3.kt:20)
    at Test2_3Kt.main(test2_3.kt:25)

when表達式並不僅限於檢查值是否相等,它也允許檢查when實參值的類型。這也是我們的答案。

fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> TODO()
            is Sum -> TODO()
            else -> throw IllegalArgumentException("Unknown expression")
        }

3.函數的定義與調用

Default arguments

在這裏插入圖片描述
我們首先看右側java代碼應對不同的輸入參數,就要寫多個函數。但我們能發現,假如我們只有名字的話
會依次調用這些函數

//1
public String foo(String name) {
    return foo(name, 42);
}
//2
public String foo(String name, int number) {
    return foo(name, number, false);
}
//3
public String foo(String name, int number, boolean toUpperCase) {
    return (toUpperCase ? name.toUpperCase() : name) + number;
}

也就是說number默認爲42,toUpperCase默認爲false。
接下來我們看下在kotlin中如何爲形參賦初始值,點擊鏈接

1.函數參數可以有默認值,當相應的參數被省略時使用默認值。與其他語言相比,這減少了重載的數量。
默認值在類型後使用等號賦值

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { /*...*/ }

2.如果一個有默認值的參數後跟着一個沒有默認值的參數,在使用該函數時就要使用指定實參對應哪個形參( named arguments)
如下代碼是錯誤的,Error:(7, 10) Kotlin: No value passed for parameter ‘baz’

fun foo(bar: Int = 0,baz:Int){
    println("bar is $bar,baz is $baz")
}
fun main(args: Array<String>){
    foo(0)
}

正確代碼應該是:

foo(baz = 10)

看完鏈接後應該知道todo該寫什麼了。(number默認爲42,toUpperCase默認爲false)

fun foo(name: String, number: Int=42, toUpperCase: Boolean=false) =
        (if (toUpperCase) name.toUpperCase() else name) + number

fun useFoo() = listOf(
        foo("a"),
        foo("b", number = 1),
        foo("c", toUpperCase = true),
        foo(name = "d", number = 2, toUpperCase = true)
)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章