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}
上一篇下一篇

猜你喜欢

热点阅读