kotlin中常用的高阶函数

kotlin中常用的高阶函数_第1张图片

在Kotlin中,高阶函数即指:将函数用作一个函数的参数或者返回值的函数

TODO函数

此函数的作用:显示抛出NotImplementedError错误。NotImplementedError错误类继承至Java中的Error

public class NotImplementedError(message: String = "An operation is not implemented.") : Error(message)

//TODO的源码
@kotlin.internal.InlineOnly
public inline fun TODO(): Nothing = throw NotImplementedError()

@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = 
throw NotImplementedError("An operation is not implemented: $reason")

//使用
fun main(args: Array) {
    TODO("测试TODO函数,是否显示抛出错误")
}

调用todo,如果不传参的话,就会报An operation is not implemented.

run()函数

  1. run()
    其可以运行一个代码块并返回值或者运行一个与其他完全无关的代码块
//源码
public inline fun  run(block: () -> R): R {
contract {
    callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()

val index = 3
val num = run {
    when(index){
        0 -> "kotlin"
        1 -> "java"
        2 -> "php"
        3 -> "javaScript"
        else -> "none"
    }
}.length
println("num = $num")
//输出结果为 num = 10
  1. T.run()
public inline fun  T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

val str = "kotlin"
str.run {
    println( "length = ${this.length}" )
    println( "first = ${first()}")
    println( "last = ${last()}" )
}
//输出结果为:
length = 6
first = k
last = n

在其中,可以使用this关键字,因为在这里它就代码str这个对象,也可以省略。因为在源码中我们就可以看出,block()就是一个T类型的扩展函数。
在实际开发中,我们可以:

val mTvBtn = findViewById(R.id.text)
mTvBtn.run{
    text = "kotlin"
    textSize = 13sp
    ...
}

with()函数

其实with() 函数和T.run()函数的作用是相同的,只是前者是高阶函数,后者是扩展的高阶函数

val str = "kotlin"
with(str) {
    println( "length = ${this.length}" )
    println( "first = ${first()}")
    println( "last = ${last()}" )
}
//其输出结果为:
length = 6
first = k
last = n

如果输出对象为null?,其写法不同之处

val newStr : String? = "kotlin"

with(newStr){
    println( "length = ${this?.length}" )
    println( "first = ${this?.first()}")
    println( "last = ${this?.last()}" )
}

newStr?.run { //更优雅啊
    println( "length = $length" )
    println( "first = ${first()}")
    println( "last = ${last()}" )
}

T.apply()函数

public inline fun  T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

从T.apply()源码中在结合前面提到的T.run()函数的源码我们可以得出,这两个函数的逻辑差不多,唯一的区别是T,apply执行完了block()函数后,返回了自身对象。而T.run是返回了执行的结果。
故而: T.apply的作用除了实现能实现T.run函数的作用外,还可以后续的再对此操作。下面我们看一个例子:
例:为TextView设置属性后,再设置点击事件等

val mTvBtn = findViewById(R.id.text)
mTvBtn.apply{
    text = "kotlin"
    textSize = 13f
    ...
}.apply{
    // 这里可以继续去设置属性或一些TextView的其他一些操作
}.apply{
    setOnClickListener{ .... }
}

或者:设置为Fragment设置数据传递

// 原始方法
fun newInstance(id : Int , name : String , age : Int) : MimeFragment{
        val fragment = MimeFragment()
        fragment.arguments.putInt("id",id)
        fragment.arguments.putString("name",name)
        fragment.arguments.putInt("age",age)
        
        return fragment
}

// 改进方法
fun newInstance(id : Int , name : String , age : Int) = MimeFragment().apply {
        arguments.putInt("id",id)
        arguments.putString("name",name)
        arguments.putInt("age",age)
}

T.also()函数

public inline fun  T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

跟apply()几乎一模一样,不同的是,also只能用it调用自身而apply使用this

"kotlin".also {
    println("结果:${it.plus("-java")}")
}.also {
    println("结果:${it.plus("-php")}")
}

"kotlin".apply {
    println("结果:${this.plus("-java")}")
}.apply {
    println("结果:${this.plus("-php")}")
}

T.let()函数

public inline fun  T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

let可以规避空指针,实现空安全;另外其与also和apply的不同,如下:

"kotlin".let {
    println("原字符串:$it")         // kotlin
    it.reversed()
}.let {
    println("反转字符串后的值:$it")     // niltok
    it.plus("-java")
}.let {
    println("新的字符串:$it")          // niltok-java
}

"kotlin".also {
    println("原字符串:$it")     // kotlin
    it.reversed()
}.also {
    println("反转字符串后的值:$it")     // kotlin
    it.plus("-java")
}.also {
    println("新的字符串:$it")        // kotlin
}

"kotlin".apply {
    println("原字符串:$this")     // kotlin
    this.reversed()
}.apply {
    println("反转字符串后的值:$this")     // kotlin
    this.plus("-java")
}.apply {
    println("新的字符串:$this")        // kotlin
}

T.takeIf()函数

public inline fun  T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

从源码可以看出,这是一个关于条件判断的函数:传入一个你希望的一个条件,如果对象符合你的条件则返回自身,反之,则返回null

val str = "kotlin"

val result = str.takeIf {
    it.startsWith("ko") 
}

println("result = $result")    //kotlin

T.takeUnless()函数

public inline fun  T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

跟takeif恰好相反:传入一个你希望的一个条件,如果对象符合你的条件则返回null,反之,则返回自身。

val str = "kotlin"

val result = str.takeUnless {
    it.startsWith("ko") 
}

println("result = $result")    // null

repeat()函数

public inline fun repeat(times: Int, action: (Int) -> Unit) {
    contract { callsInPlace(action) }

    for (index in 0..times - 1) {
        action(index)
    }
}
repeat(5){
    println("我是重复的第${it + 1}次,我的索引为:$it")
}

输出结果为:

我是重复的第1次,我的索引为:0
我是重复的第2次,我的索引为:1
我是重复的第3次,我的索引为:2
我是重复的第4次,我的索引为:3
我是重复的第5次,我的索引为:4

lazy()函数

顾名思义其用作延时,延迟初始化即:指当程序在第一次使用到这个变量(属性)的时候在初始化。

  • 使用lazy{}高阶函数,不能用于类型推断。且该函数在变量的数据类型后面,用by链接。
  • 必须是只读变量,即用val声明的变量
// 声明一个延迟初始化的字符串数组变量
private val mTitles : Array by lazy {
    arrayOf(
            ctx.getString(R.string.tab_title_android),
            ctx.getString(R.string.tab_title_ios),
            ctx.getString(R.string.tab_title_h5)
    )
}

// 声明一个延迟初始化的字符串
private val mStr : String by lazy{
    "我是延迟初始化字符串变量"
}

再详细的,大家可以参考这里

你可能感兴趣的:(Android,kotlin,android,java)