User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Kotlin   ›   Kotlin Notes   ›   正文
Kotlin Notes

Kotlin-函数进阶—内联函数(十六)

2021-01-17 21:05:08
1282  0 0
参考目录 隐藏
1) 内联函数
2) 非局部返回
3) return 例子:
4) crossline注解
5) 禁用内联 noinline
6) 具体化的类型参数

阅读完需:约 6 分钟

内联函数

内联函数使用关键字内联声明,内联函数的使用增强了高阶函数的性能。 内联函数告诉编译器将参数和函数复制到调用站点。

forEash 本身就是一个内联函数因为函数前面有inline,为我们创建了一个for循环

这就是内联函数调用for循环而来的内容

inline 修饰符影响函数本身和传给它的 lambda 表达式:所有这些都将内联到调用处。 内联可以理解为嵌入到调用处,避免函数的反复调用

虚函数或局部函数不能声明为内联。 以下是内联函数内部不支持的一些表达式和声明:

  • 局部类声明
  • 内部嵌套类的声明
  • 函数表达式
  • 声明局部函数
    局部可选参数的默认值

让我们看一下内联函数的基本示例:

fun main(args: Array<String>) {
    inlineFunction({ println("调用内联函数")})
}

inline fun inlineFunction(myFun: () -> Unit ) {
    myFun()
    print("内联函数内的代码")
}

执行上面示例代码,得到以下结果 – 

调用内联函数
内联函数内的代码


非局部返回

在 Kotlin 中,我们可以只使用一个正常的、非限定的 return 来退出一个命名或匿名函数。这意味着要退出一个 lambda 表达式,我们必须使用一个标签,并且在 lambda 表达式内部禁止使用裸 return,因为 lambda 表达式不能使包含它的函数返回:

fun foo() {
    ordinaryFunction {
        return // 错误:不能使 `foo` 在此处返回
    }
}

但是如果 lambda 表达式传给的函数是内联的,该 return 也可以内联,所以它是允许的:

fun foo() {
    inlined {
        return // OK:该 lambda 表达式是内联的
    }
}

这种返回(位于 lambda 表达式中,但退出包含它的函数)称为非局部返回。 我们习惯了在循环中用这种结构,其内联函数通常包含:

fun hasZeros(ints: List<Int>): Boolean {
    ints.forEach {
        if (it == 0) return true // 从 hasZeros 返回
    }
    return false
}

return 例子:

fun main(args: Array<String>) {
    inlineFunction({ println("调用内联函数")
        return},{ println("内联函数中的下一个参数")})
}

inline fun inlineFunction(myFun: () -> Unit, nxtFun: () -> Unit) {
    myFun()
    nxtFun()
    print("内联函数内的代码")
}

执行上面示例代码,得到以下结果 – 

调用内联函数

crossline注解

一些内联函数可能调用传给它们的不是直接来自函数体、而是来自另一个执行上下文的 lambda 表达式参数,例如来自局部对象或嵌套函数。在这种情况下,该 lambda 表达式中也不允许非局部控制流。

要防止从lambda表达式和内联函数本身返回,可以将lambda表达式标记为crossinline。 如果在lambda表达式中找到了return语句,则会抛出编译器错误。

inline fun f(crossinline body: () -> Unit) {
    val f = object: Runnable {
        override fun run() = body()
    }
    // ……
}

fun main(args: Array<String>) {
    inlineFunction({ println("calling inline functions")
        return // compile time error
    },{ println("next parameter in inline functions")})
}

inline fun inlineFunction(crossline myFun: () -> Unit, nxtFun: () -> Unit) {
    myFun()
    nxtFun()
    print("code inside inline function")
}

禁用内联 noinline

在内联函数中,当想要将内联函数中传递的一些lambda作为内联函数时,使用noinline修饰符标记其他函数参数。它用于设置不在调用中内联的表达式。

fun main(args: Array<String>) {
    inlineFunctionExample({  println("调用内联函数")},
        {  println("内联函数中的下一个参数")} )

    println("这是关闭main函数")
}

inline fun inlineFunctionExample(myFun: () -> Unit, noinline nxtFun: () -> Unit  ) {
    myFun()
    nxtFun()
    println("内联函数内的代码")
}

执行上面示例代码,得到以下结果 – 

调用内联函数
内联函数中的下一个参数
内联函数内的代码
这是关闭main函数

如果内联函数不包含noinline函数参数且没有reified(具体)类型参数,则编译器将生成警告。

这个是为了满足inline特性而设计的语法糖,因为给函数使用内联之后,编译器会用其函数体来替换掉函数调用,而如果该函数里面有泛型就可能会出现编译器不懂该泛型的问题,所以引入reified,使该泛型被智能替换成对应的类型


具体化的类型参数

有时候我们需要访问一个作为参数传给我们的一个类型:

fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
    var p = parent
    while (p != null && !clazz.isInstance(p)) {
        p = p.parent
    }
    @Suppress("UNCHECKED_CAST")
    return p as T?
}

在这里我们向上遍历一棵树并且检查每个节点是不是特定的类型。这都没有问题,但是调用处不是很优雅:

treeNode.findParentOfType(MyTreeNode::class.java)

我们真正想要的只是传一个类型给该函数,即像这样调用它:

treeNode.findParentOfType<MyTreeNode>()

为能够这么做,内联函数支持具体化的类型参数,于是我们可以这样写:

inline fun <reified T> TreeNode.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) {
        p = p.parent
    }
    return p as T?
}

我们使用 reified 修饰符来限定类型参数,现在可以在函数内部访问它了,几乎就像是一个普通的类一样。由于函数是内联的,不需要反射,正常的操作符如 !is和 as 现在都能用了。此外,我们还可以按照上面提到的方式调用它:myTree.findParentOfType<MyTreeNodeType>()。虽然在许多情况下可能不需要反射,但我们仍然可以对一个具体化的类型参数使用它:

inline fun <reified T> membersOf() = T::class.members

fun main(s: Array<String>) {
    println(membersOf<StringBuilder>().joinToString("\n"))
}

普通的函数(未标记为内联函数的)不能有具体化参数。不具有运行时表示的类型(例如非具体化的类型参数或者类似于Nothing的虚构类型)不能用作具体化的类型参数的实参。


如果改变了属性的get/set方法使之变成内联,那么属性内部会自动引用调用的那个属性

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594517浏览

随机文章
Webpack-dev-server的proxy用法(Vue跨域)
5年前
Spring—Assert断言测试(旧)(常用方法)
5年前
Kotlin-函数进阶—集合变换和序列(十七)
4年前
Mybatis(Plus)—代码生成器
5年前
SpringSecurity—AuthenticationManagerBuilder (认证管理器分析)
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594517 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付