Kotlin里的takeIf和takeUnless

Posted 炎之铠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin里的takeIf和takeUnless相关的知识,希望对你有一定的参考价值。

介绍

我们使用kotlin的时候,会经常用到一些如let、apply、run这些作用域函数,它能让我们方便、简洁地链式调用对象的方法,除了这些,Kotlin标准库还提供了 takeIf 函数和 takeUnless 函数. 这些函数允许你在链式调用中加入对象的状态检查。

官方文档在此

使用场景

我们在写if语句的时候经常会遇到这样的场景:前面调用了一个函数计算得出了一个结果,现在需要对这个结果做一个分支判断,并且我们只需要用到if的一个分支时,可以用takeIf和takeUnless代替

如:

    fun testWithoutTakeIf() 
        val name = "yanzhikai"
        val hasYan = name.indexOf("yan")
        Log.i(TAG, "testWithoutTakeIf: hasYan = $hasYan")
        if (hasYan >= 0) 
            Log.i(TAG, "testWithoutTakeIf: has yan")
        
        Log.i(TAG, "testWithoutTakeIf: $name")
    
    
输出:
I: testWithoutTakeIf: hasYan = 0
I: testWithoutTakeIf: has yan
I: testWithoutTakeIf: yanzhikai

可以写成:

    fun testTakeIf() 
        val name = "yanzhikai"
        name.indexOf("yan")
            .takeIf 
                Log.i(TAG, "testTakeIf: it = $it")
                it >= 0
            
            ?.let 
                Log.i(TAG, "testTakeIf: has yan")
            
        Log.i(TAG, "testTakeIf: $name")
    
   
输出:
I: testTakeIf: it = 0
I: testTakeIf: has yan
I: testTakeIf: yanzhikai

用法

takeIf

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? 
  • 是扩展函数
  • 上下文对象的引用方式:it
  • 返回值:如果代码块predicate里面返回为true,则返回这个对象本身,否则返回空
  • 使用注意:结果要用?判空

takeUnless

public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?
  • 是扩展函数
  • 上下文对象的引用方式:it
  • 返回值:如果代码块predicate里面返回为false,则返回这个对象本身,否则返回空
  • 使用注意:结果要用?判空

说明

从上面的用法可见它们之间的区别就只有一个是满足代码块里面的条件才返回对象本身,一个是不满足条件才返回,如例子用takeUnless写可以写成:

    fun testTakeUnless() 
        val name = "yanzhikai"
        name.indexOf("yan")
            .takeUnless 
                Log.i(TAG, "testTakeUnless: it = $it")
                it < 0
            
            ?.let 
                Log.i(TAG, "testTakeUnless: has yan")
            
        Log.i(TAG, "testTakeUnless: $name")
    
    
输出:
I: testTakeUnless: it = 0
I: testTakeUnless: has yan
I: testTakeUnless: yanzhikai

优点

  • 可以配合其他作用域函数返回的结果,做出单向判断,保持链式调用

  • 简化写法,逻辑清晰,减少代码量,代码更优雅(可以装逼)。

缺点

  • 太简洁也是罪,如果返回值和takeXx写在一起时,debug无法进去看到it的值(所以建议比较重要的值可以分行写或者打印出来)

  • 提升代码阅读者的理解难度(毕竟if谁都懂,takeXx要学)

如果需要两个分支?

此时也可以用takeIf和takeUnless,可以加上elvis 操作符来做第二个分支的操作:

        name.indexOf("yan")
            .takeIf 
                Log.i(TAG, "testTakeIf: it = $it")
                it >= 0
            
            ?.let 
                Log.i(TAG, "testTakeIf: has yan")
            ?: Log.i(TAG, "testTakeIf: no yan")

不过不建议这样做,这样不仅增加了代码理解难度,而且后续维护也比较难(?:后面只能跟一个语句),还不如直接用作用域函数+判断:

        name.indexOf("yan")
            .let 
                Log.i(TAG, "testTakeIf: it = $it")
                if (it >= 0) 
                    Log.i(TAG, "testTakeIf: has yan")
                 else 
                    Log.i(TAG, "testTakeIf: no yan")
                
            

以上代码地址

总结

  • takeIf和takeUnless作用:根据代码块里面的返回值,决定返回空还是this本身,配合?.作用域函数来做判断
  • 使用场景:只需要单个if分支语句的时候
  • 优点
    • 可以配合其他作用域函数返回的结果,做出单向判断,保持链式调用
    • 简化写法,逻辑清晰,减少代码量,代码更优雅
  • 缺点
    • 如果返回值和takeXx写在一起时,debug无法进去看到it的值
    • 提升代码阅读者的理解难度

上述意见乃是个人经验之谈,如果错漏,敬请指正

以上是关于Kotlin里的takeIf和takeUnless的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin takeIf takeUnless

Kotlin标准库函数 ④ ( takeIf 标准库函数 | takeUnless 标准库函数 )

Kotlin标准库函数总结 ( apply 函数 | let 函数 | run 函数 | with 函数 | also 函数 | takeIf 函数 | takeUnless 函数 )

Kotlin标准库函数总结 ( apply 函数 | let 函数 | run 函数 | with 函数 | also 函数 | takeIf 函数 | takeUnless 函数 )

Kotlin范围函数:Android EditText支持* apply *,* let *和* run *但不支持* with *

kotlin的takeIf简单使用理解