Kotlin學習:高級特性姿勢

高級特性

1、解構

class User(var  age:Int,var name:String){
    //operator將一個函數標記爲重載一個操作符或者實現一個約定
    operator fun component1() = age
    operator fun component2() = name
}

fun main() {
    var user = User(12,"aaa")
    var (age,name) = user
}

在賦值的時候 調用component1和2這兩個方法賦值給第一個、第二個元素。

解構更常見於map:

fun main() {
   var map = mapOf<String,String>("1" to "key1","2" to "key2")
    for((k,v) in map){
        println("key:$k,value:$v")
    }
}

2、循環和集合操作符

五種循環語法:

fun main() {
   for(i in 1..10){
       println(i)
   }
    for(i in 1 until 10){
        println(i)
    }
    for(i in 10 downTo 1){
        println(i)
    }
    for(i in 1..10 step 2){

    }
    repeat(10){
        println(it)
    }
}

遍歷集合:

fun main() {
   var list = arrayListOf<String>("a","b","c")
    for(str in list){
        println(str)
    }
    for((index,str) in list.withIndex()){
        println("$index ,,, $str")
    }

}

3、集合操作符:

fun main() {
    var list = arrayListOf<Char>('a','b','c','d')
    //返回符合條件的第一個
    val a = list.map { it - 'a' }.filter { it > 0 }.find { it > 1 }
}

fun demo(){
    var a = arrayOf("4","0","i","f","w","0","9")
    var index = arrayOf(5,3,9,4,8,31,9,2,1,7)
    index.filter {
        it < a.size
    }.map {
        a[it]
    }.reduce{
        s , s1 -> "$s$s1"
    }.also {
        println(it)
    }
}

filter就像過濾器一樣,篩選出符合條件的。map是可以改變返回的數據類型的,原先返回值是int,現在返回值是String。reduce可以取出兩個拼接字符串,最後also輸出結果。

常用操作符:

4、作用域函數

fun main() {
    val user = User("zhangsan")
    //let和run都會返回閉包的執行結果,區別在於let閉包有參數,而run閉包沒有參數
   var letResult:String = user.let { user:User -> "let::${user.javaClass}" }
    println(letResult)
    var runResult:String = user.run { "run::${this.javaClass}" }

    //also與apply都不返回閉包的執行結果,區別在於also有閉包參數,而apply沒有閉包參數
    user.also {
        println("also::${it.javaClass}")
    }
    user.apply {
        println("apply::${this.javaClass}")
    }

    //takeIf的閉包返回一個判斷結果,爲false時,takeIf函數會返回null
    //takeUnless 與 takeIf剛好相反,閉包的判斷結果,爲true時,函數返回null
    user.takeIf { it.name.length > 0 }?.also { println("name:${it.name}") } ?: println("name:null")
    user.takeUnless { it.name.length > 0 }?.also { println("name:null") } ?: print("name:${user.name}")

    //重複執行當前閉包
    repeat(5){
        println(user.name)
        print(it)
    }

    //with比較特殊,是一個頂級函數,與下面的apply類似
    with(user){
        this.name = "with"
    }
    //user.apply { this.name = "with" }

 

5、中綴表達式

fun main() {
    for(i in 1..100 step 20){
        println(i)
    }

}
//實際上這個代碼在編譯後就變成了一個方法,來幫我們實現這樣的一種簡寫,這個就是運算符重載
//通過operator實現,rangeTo的方法

手寫一箇中綴表達式:

fun main() {
    println(5 vs 6)
}

sealed class CompareResult{
    object LESS:CompareResult(){
        override fun toString(): String {
            return "小於"
        }
    }
    object MORE:CompareResult(){
        override fun toString(): String {
            return "大於"
        }
    }
    object EQUAL:CompareResult(){
        override fun toString(): String {
            return "等於"
        }
    }

}

infix fun Int.vs(num:Int):CompareResult =
        if(this - num < 0){
            CompareResult.LESS
        }else if(this - num > 0){
            CompareResult.MORE
        }else{
            CompareResult.EQUAL
        }

用infix關鍵字定義運算符重載函數

6、DSL(領域專用語言:json、xml..巴拉巴拉)

自己感興趣可以查一查。

7、val和var的本質區別

var 對象實際上是擁有getter和setter方法的,val是沒有setter方法的,但是我們可以重寫get方法達到某種變得目的。

這個是var修飾得數據:

class demo{
    var a:Int = 1
        set(value){
            field = value
        }
        get(){return field}
}

這裏面set得時候不可以用a=value,因爲只要用a=xx這個變量就會觸發set方法。就會一直遞歸造成棧溢出。

val修飾得數據:

class demo{
    val a:Int = 1
        get(){return field}
}
fun main() {
    var demo:Demo = Demo()
    println(demo.a)
    demo.countAdd()
    println(demo.a)
}

class Demo{
    var count = 1;
    val a:Int = 1
        get(){return field + count}

    fun countAdd(){
        count++;
    }
}

我們可以在get上面做手腳達到可變的目的。輸出2、3。如果我們真想用常量,可以試着用const val關鍵字。

const val b:Int = 1;
class Demo{

    companion object {
        const val a:Int = 1;
    }
}

這個const只能修飾在object裏面,也就是我們的單例對象和類的外邊。const val只能修飾基本數據類型和String類型,在編譯期就可以知道類型的數據。

8、內聯noinline

kotlin規定:內部lambda是不允許中斷外部執行的。

而inline是可以的:

fun main() {
    test {
        print("aaaaa")
        return
    }
    print("bbbbb")
}

inline fun test(l : () -> Unit){
    l.invoke()
}

只會打印aaaaa,這是不行的。如果我們去掉inline呢?

fun main() {
    test {
        print("aaaaa")
        return@test
    }
    print("bbbbb")
}

fun test(l : () -> Unit){
    l.invoke()
}

kotlin就會讓我們return@test,表示執行完這個閉包,打印aaaaa、bbbbb。

fun main() {
    test {
        print("aaaaa")
        return@test
        print("ccccc")
    }
    print("bbbbb")
}

inline fun test(crossinline l : () -> Unit){
    l.invoke()
}

如果我們想要有inline還得輸出aaaaa,bbbbb。就只能像上面這樣做了。

9、泛型

class Test<T> where T:Runnable{
    fun add(t:T){
        t.run()
    }
}

聲明T必須是Runnable的一個子類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章