Kotlin高级入门

2020-03-20  本文已影响0人  leeeyou

示例项目地址:https://github.com/Leeeyou/SampleOfKotlin-InDepth

1. 操作符

1.1 集合操作符

元素相关的

排序相关的

过滤相关的

转换相关的

特定集合类型相关的

1.2 作用域函数

Kotlin内置的一系列可以对数据做变换的函数,与集合的操作符非常相似,但集合操作符只能用于集合,而作用域函数可以用于对所有对象做一系列操作。

- 有闭包参数 无闭包参数
返回闭包结果 let run
不返回闭包结果 also apply

takeIf的闭包返回一个判断结果,为false时,takeIf函数会返回空;takeUnless 与 takeIf 刚好相反, 闭包的判断结果,为true时函数会返回空。

with比较特殊,不是以扩展方法的形式存在的,而是一个顶级函数。

fun main() {
    val user = UserInfo(9802830, "Rose", "http://oioe.i/23.png", 1, 1, "17789876555")

    val letResult = user.let { "let::${it.nickname}" }
    println(letResult)
    val runResult = user.run { "run::${this.mobile}" }
    println(runResult)
    println("---")

    user.also {
        println("also::${it.uid}")
    }.apply {
        println("apply::${this.gender}")
    }.nickname = "hello"
    println(user.nickname)
    println("---")

    user.nickname = "Lily"
    user.takeIf { it.nickname?.length!! > 0 }?.also { println("姓名为${it.nickname}") } ?: println("姓名为空")
    user.takeUnless { it.nickname?.length!! > 0 }?.also { println("姓名为空") } ?: println("姓名为${user.nickname}")
    println("---")

    with(user) {
        this.head = "http://oioe.i/25.png"
        this.mobile = "17789876558"
    }
    println(user)

}

1.3 操作符的实现原理

本质上都是扩展函数或者是扩展函数的形式为代码做一系列的扩展操作。

//map操作示例
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}

//flatMap操作示例
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}

2. 高级特性

2.1 解构声明

就是将一个对象拆解成若干个变量,其本质将对象解析成一组属性,然后通过调用与之对应的component()方法得到属性的值,再赋值给各自的局部变量。

fun main() {
    val map = mapOf("深圳" to "中国", "孟加拉" to "印度")
    for ((city, country) in map) {
        println("$city belongs $country")
    }

    val (uid2, nickname, _, _, _, mobile) = UserInfo(9802830, "Rose", "http://oioe.i/23.png", 1, 1, "17789876555")
    println("My nickname is $nickname,uid is $uid2 , my mobile phone is $mobile")
}

2.2 中缀表达式

所谓中缀表达式就是不需要点和括号的方法调用,其本质还是函数调用。

enum class CompareResult {
    MORE, LESS, EQUAL
}

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

fun main() {
    //自定义示例
    println(1 vs 6)
    println(9 vs 6)
    println(6 vs 6)

    //库自带中缀示例 to、step
    mapOf("深圳" to "中国", "孟加拉" to "印度")

    for (i in 1..10 step 2) {
        println(i)
    }
}

2.3 内联函数的特殊性

Lambda 表达式最大的特点是可以作为参数传递。当定义一个闭包作为参数的函数,称这个函数为高阶函数。在使用高阶函数时,为了大幅提升高阶函数的性能,使用了内联函数,在编译阶段,编译器将会把内联函数拆分,直接插入到调用出。(ps:如果一个 inline 函数是很大的,那他会大幅增加调用它的那个函数的体积。)


val runnable = Runnable {
    println("runnable task...")
}

val successCallback: () -> Int = {
    println("do something task...")
    100
}

fun main() {
    //内部Lambda是不允许中断外部函数执行的
    test4(runnable::run, runnable::run)
    println("--- ---")

    //inline函数的return直接中断了外部函数的调用
    val userInfo = UserInfo(9802830, "Rose", "http://oioe.i/23.png", 1, 1, "17789876555")
    userInfo.let {
        it.mobile?.apply {
            println("$this do something background task...")
            //return
        }
    }
    println("--- ---")

    test1 {
        println("hello 1-1")
        return@test1 //可以根据实际的情况来决定是不是要执行后面的代码
        println("hello 1-1-1")
    }
    println("--- ---")

    test2(successCallback) {
        return
        println("hello 2-1")
    }
    println("--- ---")

    test3({
        println("hello 3-1")
    }, runnable::run)
}

inline fun test1(crossinline block: () -> Unit) {
    block()
    return
}

inline fun test2(noinline block1: () -> Int, block2: () -> Unit): () -> Int {
    block1.invoke()
    block2()
    println("test 2")
    return block1
}

inline fun test3(block: () -> Unit, block2: () -> Unit) {
    block.invoke()
    block2.invoke()
    println("test 3")
}

fun test4(block: () -> Unit, block2: () -> Unit) {
    block.invoke()
    block2.invoke()
    println("test 4")
}

2.4 操作符重载

运算符重载需要使用关键字operator修饰,其余定义与函数相同。 运算符的数量毕竟是有限的,有时并不一定有合适的,此时可以考虑前面的中缀表达式,要是觉得麻烦,可以直接考虑扩展函数。

data class Point(val x: Int, val y: Int)

operator fun Point.unaryMinus() = Point(-x, -y)
operator fun Point.unaryPlus() = Point(+x, +y)

val point = Point(10, 20)

fun main() {
    println(-point)  // prints "Point(x=-10, y=-20)"
    println(+point)  // prints "Point(x=-10, y=-20)"

    val listOf = listOf("深圳", "孟加拉", "拉斯维加斯")
    val myCity = "拉斯维加斯"
    println(myCity in listOf)

    println(listOf.get(0))
    println(listOf[1])
}

3. 必须掌握的命令

javap [option] xxx.class

这个命令可以反编译一个class文件,可以方便的让我们知道Kt代码在编译以后处于怎样的状态,以及帮助我们分析自己的代码。

上一篇下一篇

猜你喜欢

热点阅读