Kotlin高级

引言

本节主要描述Kotlin的高阶函数,以及also,run,let,apply等写法和其原理

声明高阶函数

声明高阶函数就像声明一个变量一样,没有具体的实现,当然它也可以被作为另一个函数的形参,传递给其他函数使用

var m1:() -> Unit   // 定义了一个无返回值。无参数的函数
var m2:(Int, Int) ->Int
// ..

定义高阶函数

var m1: (Int, Int) -> Int = {number1, number2 -> number1 + number2}
var m2: (String, String) -> Unit = {str1, str2 -> println("s1:$str1, s2:$str2")}
var m3: (Int, Int) -> Int = {i1, i2 ->
  i1 + i2  // 不需要return
}
var m4: = {number1:Int, number2:Int -> number1 + nubmer2}
var m5 = {i1:Int,i2:Int -> i1 + i2}

高阶函数作为参数

fun login(username:String, password:String,check:(String,String)->Boolean) : Boolean{
  if (check(username,password)) {
    return LoginMgr.login(username,password)
  } else {
    return false
  }
}

// 调用
fun main() {
    login("123","123") { username, password->
        TextUtils.isEmpty(username) && TextUtils.isEmpty(password)    // 这里不需要return
    }
}

高阶函数

let高阶函数

let可以拿到{}中的返回值

fun main() {
  var response: String? = "success"
  var res1 = response?.myLet{ it == "success" }
}
 
fun <T, R> T.myLet(m:(T) -> R): R = m(this)

给T传递一个myLet扩展函数,扩展函数使用了一个高阶函数,这就可以resonpse.myLet{}了,因为T是任意类型的,因此任意函数都可以调用.myLet()函数
为什么不是response.myLet()呢?原因myLet中的参数为高阶函数,因此可以直接response.myLet{}
在kotlin提供的let函数中,我们可以直接使用it来代替response的,因此,这里应该增加一个参数T,传递给m:(T)->R,从而有response.myLet{ it-> // .. }

apply高阶函数

apply依然调用者,如T.apply就返回T

response.myApply{ println(this.length) }  // 这里可以直接使用this来代替response

fun <T> T.myApply(m:T.() -> Unit): T {
  m()
  return this
}

给他T传递一个myApply的扩展函数,注意,与myLet的区别是参数m也增加了T.(),这就意味着m也成了T的扩展,因此在m中可以使用T的成员变量,和T即this。
而在response.myApply{}中也可以直接使用this

Also高阶函数

response.myAlso{ println(it.length) }  // 和apply的区别是,在高阶中不能使用this,也不能直接使用response的成员属性了

fun <T> T.myAlso(m:(T)->Unit):T{
  m(T)
  return this
}

和apply对比可知,myAlso中m:(T),传递了T参数,即如果是response调用,则在myAlso{}中可以直接使用it代替response

run高阶函数

run和let函数很类似,但在{}中不能使用T,如response.myRun{}的{}中不能使用it来代替response,也可能返回{}中返回的内容

var res = response.myRun{ true }  // res == true

fun <T, R> T.myRun(m:()->R): R = m()

with高阶函数

这个with类似于js中的with

var res = myWith(response) {  // 返回true
  length > 0  // 可以直接使用response的成员属性
}

fun <T, R> T.myWith(receiver:T, m:T.()->R): R = receiver.m()

repeat高阶函数

repeat类似一个循环,0-n的一个循环,如repeat(n),循环n次

repeat(5) {
  println(it)
}

fun repeat(times:Int, m:(Int)->Unit):Unit {
  for (index 0 until times) {
    m(index)
  }
}

isTrueThen高阶函数

response.isTrueThen{
  setStatus(it)
}

fun <R> Boolean.isTrueThen(m:(Boolean)):R? {
  if (this) {
    return m(this)
  } else {
    return null
  }
}

notEmptyThen高阶函数

response.notEmptyThen{
  doHandler(it)
}

fun <T, R> T.notEmptyThen(m:(T)->R): R? {
  if (this != null) {
    return m(this)
  } else {
    return null
  }
}

泛型读取权限

如果C extends A,则并不能使用List<A> list = new ArrayList<B>(),而只能使用List<? extends A> = new ArrayList<B>(); 或者 List<? super B> = new ArrayList<B>();
在java中,? extends A,表示只能读取,不能修改,而? super A表示只能修改不能读取
在Kotlin中,通过 out A,表示只能读取,不能修改,而in A表示只能修改不能读取


为什么有? extends A只能读,? super A只能写,试想如果相反,由于继承关系,子类的范围大于父类。那么写入的都是范围更大的类,读出来是更小的类,这就使得当写入两个节点是兄弟节点时,读出来无法强转了。
因此? extends A只能写,? super A只能读,这样就能保证写入的类不会是范围更大的类,读出来之后,可以直接函数调用

协程

Kotlin协程在Andriod中可以优雅使用,并可以减少

fun displayMethodOk() = runBlocking {  // main环境
    launch {    // main环境             
        val def = async(Dispatchers.IO) {   // 异步环境
            val result = okHttpClient.newCall(mRequest).execute().body()?.string()
        }
        // main环境
        textView.text = def.await()             
    }
}

注意,上述使用的是组赛式的协程,这就意味着在运行时,不能进行其他操作,要等待其任务完成后才能继续下一个任务。也就是非要等launch里面的任务都执行完,才能进行下一个任务。
或者

fun displayMethodOk() {
    GloableScope.lauch(Dispatchers.Main) {
        val pro = ProgressDialog(this)
        pro.setMessage("正在执行...")
        pro.show()
        // main
        withContext(Dispatchers.IO) {  // 异步
            //...
        }
        pro.hide()
    }
}

上述就是使用非组赛式,但是它像守护线程一样,当主线程挂了后,它就挂了,所以在需要增加如下写法:

fun displayMethodOk() {
    var job = GloableScope.lauch(Dispatchers.Main) {
        // ...
    }
    job.cancelJoin() // 或者直接使用 job.join()
}

总结

本节主要描述了高阶函数,泛型协变,以及协程的用法

posted @ 2021-04-14 23:36  、、、路遥  阅读(218)  评论(0)    收藏  举报