当前位置: 首页 > news >正文

Android开发(Kotlin) 高阶函数、内联函数

目录

    • 高阶函数
    • 使用高阶函数模拟类似apply函数
    • 内联函数的作用
    • noinline与crossinline
      • noinline
      • crossinline

高阶函数

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,则改函数就称为高阶函数。
kotlin有函数类型。

函数类型语法规则

(String,Int)->Unit

->左边部分用来声明改函数接收什么参数,多个参数之间用逗号类隔开。->右边部分用于声明该函数的返回值是什么,如果没有返回值就使用Unit。
示例

    fun example(func:(String, Int) -> Unit) {func("hello",456)}

高阶函数的用途允许让函数类型的参数来决定函数的执行逻辑。同一个高阶函数,只要传入不同的函数类型参数,那么它的执行逻辑和最终结果可能就完全不同。
定义一个方法,传入两个整形和一个函数类型,由传入的函数类型参数来决定做什么运算。

    fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {val result = operation(num1,num2)return  result}

定义与上面函数类型相匹配的函数。

    fun plus(num1: Int, num2: Int): Int {return num1 + num2}fun minus(num1: Int, num2: Int): Int {return num1 - num2}

使用num1AndNum2函数


fun main() {val num1 = 100val num2 = 80val result1 = num1AndNum2(num1, num2, ::plus)val result2 = num1AndNum2(num1, num2, ::minus)println("result1 is $result1,result2 is $result2")
}

结果

result1 is 180,result2 is 20Process finished with exit code 0

::plus,是一种函数引用的写法。
lambda表达式是常用的高阶函数调用方式。

fun main() {val num1 = 100val num2 = 80val result1 = num1AndNum2(num1, num2) { num1, num2 ->num1 + num2}val result2 = num1AndNum2(num1, num2) { num1, num2 ->num1 - num2}println("result1 is $result1,result2 is $result2")
}

使用高阶函数模拟类似apply函数

fun StringBuilder.build(block: StringBuilder.() -> Unit): StringBuilder{block()return  this
}

这是一个扩展函数,这个函数接收了一个函数型参数。这个函数类型参数有一点不同,在函数类型的前面加上了一个StringBuilder,表示这个函数类型是定义在那个类中的。
函数类型定义到Stringbuilder类中,好处是传入的lambda表达式将会自动拥有Stringbuilder的上下文。
示例代码

fun main() {val list = listOf<String>("Apple", "Banana", "Orange")val result = StringBuilder().build {append("Start\n")for (str in list) {append(str).append("\n")}append("end\n")}println(result.toString())
}

结果

Start
Apple
Banana
Orange
endProcess finished with exit code 0

内联函数的作用

kotlin的高阶函数每次调用都会创建一个匿名类,会造成额外的开销,内联函数可以将lambda表达式带来的运行时开销完全消除。

在定义的高阶函数前面加上inline关键字即可。

inline  fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {val result = operation(num1, num2)return result
}

noinline与crossinline

noinline

当一个高阶函数有多个函数类型的参数,我们只想内联其中一个函数类型的参数,就要使用noinline。

inline  fun inlineTest(block1:()-> Unit,noinline block2: () -> Unit){}

为什么有noinline关键字来排除内联功能?因为内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数类型参数可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数值允许传递给另外一个内联函数。
内联函数所引用的lambda表达式是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。
示例

fun main() {println("main start")val str= ""printString(str){s ->println("lambda start")if(s.isEmpty()){return@printString//局部返回}println("lambda end")}println("main end")
}fun printString(str: String, block: (String) -> Unit) {println("printString begin")block(str)println("printString end")
}

执行结果

main start
printString begin
lambda start
printString end
main endProcess finished with exit code 0

查看结果,lambda end没有被打印出来,printString end被打印出来了,说明return@printString只能进行局部返回。
将printString()函数声明称成一个内联函数

fun main() {println("main start")val str= ""printString(str){s ->println("lambda start")if(s.isEmpty()){return}println("lambda end")}println("main end")
}inline  fun printString(str: String, block: (String) -> Unit) {println("printString begin")block(str)println("printString end")
}

执行结果

main start
printString begin
lambda startProcess finished with exit code 0

此时的return代表的事返回外层的调用函数,就是main().

crossinline

inline  fun runRunnable(block: () -> Unit) {val runnable = Runnable {block()}
}

上面这段代码没有inline 可以正常运行,加上inline 就报错。
在这里插入图片描述

原因解释,在runRunnable()函数中,创建了一个Runnable对象,并在Runnable的Lambda表达式中调用了传入的函数类型参数,而lambda表达式在编译的时候会被转换成匿名类的实现方式。内联函数所引用的lambda表达式允许使用return关键字进行函数返回,但由于是在匿名类中调用的函数类型参数,是不能进行外层调用函数返回的,只能对匿名类中的函数进行返回,所以提示错误。

这种情况使用crossinline关键字就可以编译通过。

inline  fun runRunnable(crossinline  block: () -> Unit) {val runnable = Runnable {block()}
}

crossinline的作用,因为内联函数的lambda表达式中允许使用return关键字,和高阶函数的匿名类实现中不允许使用return关键字之间造成了冲突。而crossinline关键字就像一个契约,用于在内联函数的lambda表达式中一定不会使用return关键字。
声明crossinline之后,无法在调用runRunnable()函数时的lambda表达式中使用return关键字进行函数返回,但仍可以使用return@runRunnable的写法来进行局部返回。

http://www.dtcms.com/a/581718.html

相关文章:

  • AI安全与网络安全的融合:从挑战到解决方案
  • 从零开始构建现代化React应用:最佳实践与性能优化
  • 国外的网站建设公司广州工商注册服务中心
  • 【tips】常用不同状态小圆点样式css
  • 保险微网站制作公司网站费用计入什么科目
  • SSM网上水果商城s7436(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 北京市建设信息网站湖南手机版建站系统信息
  • 【函数参数传递方式选择指南(C/C++)】
  • 做ppt的图片素材网站数字营销成功案例
  • 企业网站子页面模板网站 开发 外包
  • 机器学习日报14
  • 解决Mac不能识别#include <bits/stdc++.h> 头文件问题
  • 基于站点数据进行遥感机器学习参数反演-以XGBOOST反演LST为例(附带数据与代码)试读
  • 四面山网站建设现在帮别人做网站赚钱不
  • 破解EEG逆问题:ADMM-ESINet如何融合优化理论与深度学习实现实时源成像
  • CSS 高中低部分面试题方法及知识点介绍
  • GMI Cloud@AI周报 | Cursor 2.0发布自研模型Composer;小鹏发布新一代人形机器人 IRON
  • 莱芜手机网站建设报价网站建设平台策划
  • 【jmeter】-安装-插件安装
  • 猫头虎AI分享:CodeBuddy IDE 已支持 GLM-4.6!亲测更强了
  • 云手机能够流畅运行大型游戏吗
  • 【App开发】手机投屏的几种方式(含QtScrcpy)- Android 开发新人指南
  • 云手机 一梦江湖畅玩搬砖
  • 智享账单管理利器:Rachoon
  • 惠州网站小程序建设点网站制作的评价标准
  • Ascend C流与任务管理实战:构建高效的异步计算管道
  • 阶段性总结
  • AXI UART Lite v2.0 IP使用——ZYNQ学习笔记19
  • 延吉做网站建设通查询设通网站
  • Android创建本地plugin工程