Kotlin的高阶函数

一、高阶函数介绍

在Kotlin中,高阶函数即指:将函数用作一个函数的参数或者返回值的函数。

1.1、将函数用作函数参数的情况的高阶函数

// sumBy函数的源码
public inline fun CharSequence.sumBy(selector: (Char) -> Int): Int {
    var sum: Int = 0
    for (element in this) {
        sum += selector(element)
    }
    return sum
}

所以这个函数的作用是:把字符串中的每一个字符转换为Int的值,用于累加,最后返回累加的值

val testStr = "abc"
val sum = testStr.sumBy { it.toInt() }
println(sum)

1.2、将函数用作一个函数的返回值的高阶函数

fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}

1.3、高阶函数的使用

在上面的两个例子中,我们出现了str.sumBy{ it.toInt }这样的写法。其实这样的写法在前一章节Lambda使用中已经讲解过了。这里主要讲高阶函数中对Lambda语法的简写。

从上面的例子我们的写法应该是这样的:

str.sumBy( { it.toInt } )

但是根据

Kotlin中的约定,即当函数中只有一个函数作为参数,并且您使用了lambda表达式作为相应的参数,则可以省略函数的小括号()。故而我们可以写成:

str.sumBy{ it.toInt }

还有一个约定,即当函数的最后一个参数是一个函数,并且你传递一个lambda表达式作为相应的参数,则可以在圆括号之外指定它。故而上面例2中的代码我们可写成:

str.sumBy{ it.toInt }

二、自定义高阶函数

private fun resultByOpt(num1 : Int , num2 : Int , result : (Int ,Int) -> Int) : Int{
    return result(num1,num2)
}

fun main() {
    val result1 = resultByOpt(1,2){
        num1, num2 ->  num1 + num2
    }

    val result2 = resultByOpt(3,4){
        num1, num2 ->  num1 - num2
    }

    val result3 = resultByOpt(5,6){
        num1, num2 ->  num1 * num2
    }

    val result4 = resultByOpt(6,3){
        num1, num2 ->  num1 / num2
    }

    println("result1 = $result1")
    println("result2 = $result2")
    println("result3 = $result3")
    println("result4 = $result4")
}

三、常用的标准高阶函数介绍

1、T.apply()函数

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

T.apply执行完了block()函数后,返回了自身对象。

block()这个函数参数是一个扩展在T类型下的函数。这说明我的block()函数可以可以使用当前对象的上下文。所以当我们传入的lambda表达式想要使用当前对象的上下文的时候,我们可以使用这个函数。

val mTvBtn = findViewById<TextView>(R.id.text)
mTvBtn.apply{
    text = "kotlin"
    textSize = 13f
    ...
}.apply{
    // 这里可以继续去设置属性或一些TextView的其他一些操作
}.apply{
    setOnClickListener{ .... }
}

2、T.also()函数

public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

从上面的源码在结合T.apply函数的源码我们可以看出: T.also函数中的参数block函数传入了自身对象。故而这个函数的作用是用用block函数调用自身对象,最后在返回自身对象

这里举例一个简单的例子,并用实例说明其和T.apply的区别

例:

"kotlin".also {    
     println("结果:${it.plus("-java")}")
}.also {    
    println("结果:${it.plus("-php")}")
}
     
"kotlin".apply {    
     println("结果:${this.plus("-java")}")
}.apply {    
     println("结果:${this.plus("-php")}")
}

他们的输出结果是相同的:

结果:kotlin-java
结果:kotlin-php
结果:kotlin-java
结果:kotlin-php

3、T.let()函数

public inline fun <T, R> T.let(block: (T) > R): R {    
     contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
     return block(this)
}
"kotlin".let {
     println("原字符串:$it")
     it.reversed()
 }.let {
     println("反转字符串后的值:$it")
     it.plus("-java")
 }.let {
     println("新的字符串:$it")
 }
 "kotlin".also {
     println("原字符串:$it")
     it.reversed()
 }.also {
     println("反转字符串后的值:$it")
     it.plus("-java")
 }.also {
     println("新的字符串:$it")
 }
 "kotlin".apply {
     println("原字符串:$this")
     this.reversed()
 }.apply {
     println("反转字符串后的值:$this")
     this.plus("-java")
 }.apply {
     println("新的字符串:$this")
 }
原字符串:kotlin
反转字符串后的值:niltok
新的字符串:niltok-java

原字符串:kotlin
反转字符串后的值:kotlin
新的字符串:kotlin

原字符串:kotlin
反转字符串后的值:kotlin
新的字符串:kotlin

类似文章

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注