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的一个子类。

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