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

Kotlin进阶(二)中缀、内联、高阶函数

前言:被Elon Musk圈粉后,觉得他一定是我一辈子的偶像,他正做着一些那些梦寐以求,人类最浪漫最伟大的事情.

1.接收者的函数字面值

首先更正下我在 Kotlin 进阶教程(一)文末分析apply源码的一个错误:

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
复制代码

这个内联函数,是一个关于T的扩展函数,其入参block的写法,看上去好像不太好理解;T.()是什么玩意?最初我也把它理解成了T的扩展函数,这个理解是不对的,更正一下.虽然它的样子很像扩展函数,但它并不是;它是一个带有接收者的函数字面值. 接受者的函数字面值,怎么理解呢; eg: 匿名函数语法允许直接指定函数字面值的接收者类型 所以可以如下定义一个匿名函数sum

val sum = fun Int.(another: Int): Int = this + another
复制代码

this代表调用者本身,那么,我就可以这样调用sum; eg:

val sum = 2.sum(3).sum(4)
println("$sum")
复制代码

输出9; 显而易见,我们可以让调用者也成为入参的一部分,this表示; 所以apply函数可以轻松实现链式调用;

2.中缀函数

观察如下代码

val map = mapOf<Int, String>(1 to "one", 2 to "two")
复制代码

可以看到1 to "one" 很方便映射了key-value 点进去看一下源码

public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
复制代码

可以看到这个to函数是一个A的扩展函数,入参是B,所以我猜想 to 函数还可以这样调用 1.to("one"); 并且有infix修饰,infix即中缀函数的修饰符; 很显然1.to("one"),1 to one比较,后者更加简洁优雅; 对于中缀函数,它只能有一个参数,切有infix修饰;

了解了中缀函数,那么我们可以利用它发挥你的想象力,创造一些十分优雅的API .比如我们计算某个天数前的时间戳可以这么写:

 val yesterday = 1 days ago
 val theDayBeforeYesterday= 2 days ago
复制代码

代码看上就想在写英文语句一样;

object ago	  
infix fun Int.days(ago: ago):Long {
....//计算时间
return time
}
复制代码

3.内联函数

内联函数用inline修饰 在使用高阶函数时会带来一些运行时的效率损失:每一个函数都是一个对象,并且会得到一个闭包; 在(一)中我提过inline函数编译器会将函数编译成执行的代码块,从而避免了函数频繁的压栈和出栈. 我们可以看到Kotlin的源码中,尤其是标准库,大量使用了内联函数,内联函数会是性能有所提升; 所以在我们开发中,一些工具性函数,推荐liline函数;

lambda表达式中禁止裸用return进行函数返回,但是如果lambda 表达式传给的函数是内联的,该 return也可以内联,所以它是允许的:

fun foo() {

lambda { _: Int, _: Int ->
           println("内部已返回")
            return //方法内联,所以这里是OK的
            println("内部未返回")

        }

 println("lambda局部返回,后续代码执行")
}

 inline fun lambda( o: (x: Int, y: Int) -> Unit) {
        o.invoke(3, 4)
    }
复制代码

执行foo(),输出:内部已返回; 可以看到这里的return非局部返回

但是如果传入的lambda是内联的,但是又不允许其非局部控制流,那么需要用crossinline修饰 eg:

fun foo() {

lambda { _: Int, _: Int ->
           println("内部已返回")
          //  return //方法内联,但是crossinlie修饰,所以这里是不允许的,
			return@lambda //标签是允许的
            println("内部未返回")

        }

 println("lambda局部返回,后续代码执行")
}
inline fun lambda( crossinline o: (x: Int, y: Int) -> Unit) {
        o.invoke(3, 4)
    }
复制代码

执行foo(),输出:

内部已返回

lambda局部返回,后续代码执行

结尾

有理解错误的请指正!!! 重要的事情说三遍: kotlin很好用!

kotlin很好用!

kotlin很好用!

相关文章:

  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 【MySQL 5.7参考手册】8.14.2 General Thread States
  • 深入浅出的webpack构建工具---devTool中SourceMap模式详解(四)
  • 常见大数据系统所要解决问题的简要汇总
  • oracle 导入导出功能
  • [玄学]JZOJ 5811 简单的填数
  • Git基本命令(转)
  • tplink路由器DMZ设置
  • Hyperledger Composer评测
  • 实现DevOps开源工具整合之SonarScanner软件安装
  • installation failed with message INSTALL_FAILED_INSUFFICIENT_STORG
  • 集群和分布式
  • Android源码个个击破之MediaRecorder
  • Hexo+码云+git快速搭建免费的静态Blog
  • python 数据格式转换
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • es6要点
  • Laravel5.4 Queues队列学习
  • Protobuf3语言指南
  • Redis 懒删除(lazy free)简史
  • Spring核心 Bean的高级装配
  • windows下使用nginx调试简介
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 将回调地狱按在地上摩擦的Promise
  • 深度解析利用ES6进行Promise封装总结
  • 算法系列——算法入门之递归分而治之思想的实现
  • 优秀架构师必须掌握的架构思维
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #大学#套接字
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (03)光刻——半导体电路的绘制
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (C++)八皇后问题
  • (二)pulsar安装在独立的docker中,python测试
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (一)为什么要选择C++
  • (状压dp)uva 10817 Headmaster's Headache
  • **PHP分步表单提交思路(分页表单提交)
  • .htaccess配置重写url引擎
  • .NET的数据绑定
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net反编译工具
  • .NET构架之我见
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @Documented注解的作用
  • @ModelAttribute使用详解