Kotlin中的内联函数、扩展函数、语法糖
2021-06-28 本文已影响0人
千夜零一
内联函数
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
这个内联函数,是一个关于T的扩展函数。
为什么要用内联函数?
内联函数用inline修饰;在使用高阶函数时会带来一些运行时的效率损失:每一个函数都是一个对象,并且会得到一个闭包;inline函数编译器会将函数编译成执行的代码块,从而避免了函数频繁的压栈和出栈. 我们可以看到Kotlin的源码中,尤其是标准库,大量使用了内联函数,内联函数会是性能有所提升; 所以在我们开发中,一些工具性函数,推荐inline函数。
扩展函数
给类的方法做扩充,新增方法,而又不影响类的本身。
class DogKt {
fun run() = "狗会跑"
fun cry() = "狗会汪汪"
}
private fun DogKt.order() = "扩展功能-》狗听从指令"
@Test
fun main() {
var ex = DogKt()
println(ex.run())
println(ex.cry())
println(ex.order()) //此时order函数就是扩展函数
/**
* 打印结果:
* I/System.out: 狗会跑
* I/System.out: 狗会汪汪
* I/System.out: 扩展功能-》狗听从指令
*/
}
高阶函数
高阶函数是将【函数】用作 参数 或 返回值 的函数。
将 Android 里点击事件的监听用 Kotlin 来实现,它就是一个典型的高阶函数
。
// 函数作为参数的高阶函数
// ↓
fun setOnClickListener(l: (View) -> Unit) { ... }
系统标准高阶函数又被称为"语法糖",他们都是内联函数
介绍
Kotlin - 函数式编程
Kotlin的语法糖放在Standard.kt文件中,一共8个🍬。
run
(1)第一种
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
//第一种用法:相当于 r = "xxx"赋值操作
var r1 = kotlin.run { "xxxxx" }
(2)第二种
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
//第二种用法:类似于 扩展函数
var r2 = "a".run {
this.plus("b")
}
let
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
//定义:fun <T, R> T.let(block: (T) -> R): R
//功能:调用对象(T)的let函数,则该对象为函数的参数。在函数内可以通过 it 指代该对象。返回值为函数的最后一行或指定return表达式。
//类似于run,但let在使用中可用于空安全验证,变量?.let{}
val l = "a".let {
it.plus("b")
}
l?.let {
//当 l 不为null时代码执行此处
}
with
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return receiver.block()
}
/**
* with:跟run 类似
*/
val w = with("a"){ this.plus("b") }
//定义:fun <T, R> with(receiver: T, block: T.() -> R): R
//功能:将对象作为函数的参数,在函数内可以通过 this指代该对象。返回值为函数的最后一行或return表达式。
var paint1 = Paint()
paint1.color = Color.BLACK
paint1.strokeWidth = 1.0f
paint1.textSize = 18.0f
paint1.isAntiAlias = true
//使用with后:
var paint2 = Paint()
with(paint2) {
color = Color.BLACK
strokeWidth = 1.0f
textSize = 18.0f
isAntiAlias = true
}
apply
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
block()
return this
}
/**
* apply
*/
//定义:fun T.apply(block: T.() -> Unit): T
//功能:调用对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
//跟run类似,但不是返回block()而是返回自身类型,一般用于对象重新赋值情景
var paint = Paint()
paint.textSize = 14.0f
paint.color = Color.WHITE
paint.isAntiAlias = false
//使用apply后:
var painta = Paint().apply {
textSize = 14.0f
color = Color.WHITE
isAntiAlias = false
}
also
@kotlin.internal.InlineOnly@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
block(this)
return this
}
/**
* also : 跟let 类似
*/
val a = "a".also { it.plus("b") }
//定义:fun T.also(block: (T) -> Unit): T
//功能:调用对象的also函数,在函数块内可以通过 it 指代该对象,返回值为该对象本身。(注意其和let函数的区别,let返回的是最后一行,also返回的是对象本身)
//实例:需要返回对象本身(this)的情况下,例如建造者模式。
takeIf
@kotlin.internal.InlineOnly@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (predicate(this)) this else null}
//定义:fun T.takeIf(predicate: (T) -> Boolean): T?
//功能:传递一个函数参数,如果函数结果为true,返回T对象,否则返回null。//用法:/** * 一般用法var file = File("filePath")if (file.exists()) { //do something} else { return false}*///使用takeIf var file = File("filePath").takeIf { it.exists() }?:return false//do something
takeUnless
@kotlin.internal.InlineOnly@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) }
return if (!predicate(this)) this else null}
//定义:fun T.takeUnless(predicate: (T) -> Boolean): T?
//功能:与takeIf相反,参数函数返回false时返回T对象,否则返回null,这里不再举例。
repeat
@kotlin.internal.InlineOnlypublic inline fun repeat(times: Int, action: (Int) -> Unit) { contract { callsInPlace(action) }
for (index in 0 until times) { action(index) }}
//定义:fun repeat(times: Int, action: (Int) -> Unit)//功能:重复执行action函数times次,times从0开始repeat(5){ println("count:$it") }//等价于:for (i in 0..4) { println("count:$i") } /(0..4).forEach{println("count:$it")}
拓展
contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) }
这段代码几乎每个语法糖都有,他的主要存在意义就在于,要解决如下问题
if (!x.isNullOrEmpty()) {
// we know that 'x != null' here
println(x.length)
}
假设 x 是可以为 null 的,经过 isNullOrEmpty 函数判断之后,再执行 println 函数,那么它肯定就不是 null 了,就不需要再加两个 !!
来表示 x 不为 null 了,而现在的情况是要添加 !!
。
kotlin的函数式编程
/**
* 形如:
*/
class ReceiveObject{
fun exec(invoke:ReceiveObject.() -> Int){}
}
/**
* kotlin - 函数可以当变量传参
*/
fun funAsArg(args:()->Int){}
//args 代表函数,函数无参,返回值类型为Int。
fun funArg():Int{ return 1}