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

2,177 阅读3分钟

前言:被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很好用!