【Kotlin -- 知识点】高阶函数

一、什么是高阶函数

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

1. 将函数用作函数参数的情况的高阶函数

sumBy{} 高阶函数源码:

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

解释说明:

  • 该函数返回一个 Int 类型的值。并且接受了一个 selector() 函数作为该函数的参数。其中,selector() 函数接受一个 Char 类型的参数,并且返回一个Int类型的值。
  • 定义一个 sum 变量,并且循环这个字符串,循环一次调用一次 selector() 函数并加上 sum。用作累加。其中 this 关键字代表字符串本身。

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

例子:

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

输出结果:

294 // 因为字符a对应的值为97,b对应98,c对应99,故而该值即为 97 + 98 + 99 = 294

2. 将函数用作一个函数的返回值的高阶函数

lock() 函数源码:

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

解释说明:

  • 从源码可以看出,该函数接受一个 Lock 类型的变量作为参数 1,并且接受一个无参且返回类型为 T 的函数作为参数 2.
  • 该函数的返回值为一个函数,我们可以看这一句代码 return body() 可以看出。

例子:

fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized) 

3. 高阶函数的使用

这里主要讲高阶函数中对 Lambda 语法的简写:

str.sumBy( { it.toInt } )

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

str.sumBy{ it.toInt }

当函数的最后一个参数是一个函数,并且你传递一个lambda表达式作为相应的参数,则可以在圆括号之外指定它。

val result = lock(lock){
    sharedResource.operation()
}

二、自定义高阶函数

例子:传入两个参数,并传入一个函数来实现加减乘除。

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")
}

输出结果:

result1 = 3
result2 = -1
result3 = 30
result4 = 2

三、常用高阶函数

1. TODO函数

这个函数不是一个高阶函数,它只是一个抛出异常以及测试错误的一个普通函数。

作用:显示抛出 NotImplementedError 错误。NotImplementedError 错误类继承至 Java 中的
Error

例子:

fun main(args: Array<String>) {
    TODO("测试TODO函数,是否显示抛出错误")
}

输出结果:
在这里插入图片描述
如果调用 TODO() 时,不传参数的,则会输出 An operation is not implemented.

2. run 函数

run 函数这里分为两种情况讲解,采用不同的 run 函数会有不同的效果。

  • run()
    当我们需要执行一个代码块的时候就可以用到这个函数,并且这个代码块是独立的。即我可以在 run() 函数中写一些和项目无关的代码,因为它不会影响项目的正常运行。

例子:

private fun testRun1() {
    val str = "kotlin"

	run{
        val str = "java"   // 和上面的变量不会冲突
        println("str = $str")
    }
	
	println("str = $str")
}

输出结果:

str = java
str = kotlin

  • T.run()
    当我们传入的 lambda 表达式想要使用当前对象的上下文的时候,我们可以使用这个函数。

例子:

val str = "kotlin"
str.run {    
	println( "length = ${this.length}" )    
	println( "first = ${first()}")    
	println( "last = ${last()}" )
}

输出结果:

length = 6
first = k
last = n

3. with()函数

with() 函数和 T.run() 函数的作用是相同的,这两个函数的区别在于:

  • with 是正常的高阶函数,T.run() 是扩展的高阶函数。
  • with函数的返回值指定了 receiver 为接收者。

例子:

val str = "kotlin"
with(str){    
	println( "length = ${this.length}" )    
	println( "first = ${first()}")    
	println( "last = ${last()}" )
}

输出结果:

length = 6
first = k
last = n

4. T.apply()函数

从 T.apply() 源码中在结合前面提到的 T.run() 函数的源码我们可以得出,这两个函数的逻辑差不多,唯一的区别是T,apply 执行完了 block() 函数后,返回了自身对象。

例子:为TextView设置属性后,再设置点击事件

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

或者:设置为 Fragment 设置数据传递

// 原始方法
fun newInstance(id : Int , name : String , age : Int) : MimeFragment{        
	val fragment = MimeFragment()        
	fragment.arguments?.putInt("id",id)        
	fragment.arguments?.putString("name",name)        
	fragment.arguments?.putInt("age",age)        

	return fragment
}

// 改进方法
fun newInstance(id : Int , name : String , age : Int) = MimeFragment().apply {        
	arguments = Bundle()        
	arguments?.putInt("id",id)        
	arguments?.putString("name",name)        
	arguments?.putInt("age",age)
}

5. T.also()函数

T.also 函数中的参数 block 函数传入了自身对象。故而这个函数的作用是用 block 函数调用自身对象,最后在返回自身对象。

例子:

"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

6. T.let()函数

T.let 的作用也不仅仅在使用空安全这一个点上。用 T.let 也可实现其他操作

例子:

"kotlin".let {
    println("原字符串:$it")         // kotlin
    it.reversed()
}.let {
    println("反转字符串后的值:$it")     // niltok
    it.plus("-java")
}.let {
    println("新的字符串:$it")          // niltok-java
}

"kotlin".also {
    println("原字符串:$it")     // kotlin
    it.reversed()
}.also {
    println("反转字符串后的值:$it")     // kotlin
    it.plus("-java")
}.also {
    println("新的字符串:$it")        // kotlin
}

"kotlin".apply {
    println("原字符串:$this")     // kotlin
    this.reversed()
}.apply {
    println("反转字符串后的值:$this")     // kotlin
    this.plus("-java")
}.apply {
    println("新的字符串:$this")        // kotlin
}

输出结果:

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

7. T.takeIf()函数

这个函数的作用是:传入一个你希望的一个条件,如果对象符合你的条件则返回自身,反之,则返回null

例子:

val str = "kotlin"

val result = str.takeIf {
    it.startsWith("ko") 
}

println("result = $result")

输出结果:

result = kotlin

8. T.takeUnless()函数

这个函数的作用和T.takeIf()函数的作用是一样的。只是和其的逻辑是相反的。

例子:

val str = "kotlin"

val result = str.takeUnless {
    it.startsWith("ko") 
}

println("result = $result")

输出结果:

result = null

9. repeat()函数

这个函数的作用是:根据传入的重复次数去重复执行一个我们想要的动作(函数)

例子:

repeat(5){ println("我是重复的第${it + 1}次,我的索引为:$it") }

输出结果:

我是重复的第1次,我的索引为:0
我是重复的第2次,我的索引为:1
我是重复的第3次,我的索引为:2
我是重复的第4次,我的索引为:3
我是重复的第5次,我的索引为:4

10. lazy()函数

关于Lazy()函数来说,它共实现了4个重载函数,都是用于延迟操作,不过这里不多做介绍。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值