Kotlin takeIf 和 takeUnless

除了作用域函数外,标准库还包含函数 takeIftakeUnless
看看 takeIf 和 takeUnless 的实现:

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


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

takeIf : 接收一个判断条件表达式,如果判断表达式为 true 则返回对象本身,false返回 null。
takeUnless: 与 takeIf 相反, 如果判断表达式为 true 则返回 null,false 返回对象本身。

该对象可以作为 lambda 参数 (it) 使用,过滤条件位于函数的 {} 中

fun main() {
    val number = Random.nextInt(100)

    val evenOrNull = number.takeIf { it % 2 == 0 }
    val oddOrNull = number.takeUnless { it % 2 == 0 }
    println("偶数: $evenOrNull, 奇数: $oddOrNull")
}

控制台输出:
偶数: 80, 奇数: null

当在 takeIftakeUnless 之后链式调用其他函数,不要忘记执行空检查或安全调用(?.),因为他们的返回值是可为空的。

fun main() {
    val str = "Hello"
    val caps = str.takeIf { it.isNotEmpty() }?.toUpperCase()
    //val caps = str.takeIf { it.isNotEmpty() }.toUpperCase() // 编译错误
    println(caps)
}

控制台输出:
HELLO

takeIftakeUnless 与作用域函数一起特别有用。 一个很好的例子是用 let 链接它们,以便在与给定谓词匹配的对象上运行代码块。 为此,请在对象上调用 takeIf,然后通过安全调用(?.)调用 let。对于与谓词不匹配的对象,takeIf 返回 null,并且不调用 let

fun main() {
    fun displaySubstringPosition(input: String, sub: String) {
        input.indexOf(sub).takeIf { it > 0 }?.let {
            println("The substring $sub is found in $input.")
            println("Its start position is $it.")
        }
    }

    displaySubstringPosition("010000011", "11")
    displaySubstringPosition("010000011", "12")
}

控制台输出:
The substring 11 is found in 010000011.
Its start position is 7.

没有标准库函数时,相同的函数看起来是这样的:

fun main() {
    fun displaySubstringPosition(input: String, sub: String) {
        val index = input.indexOf(sub)
        if (index >= 0) {
            println("The substring $sub is found in $input.")
            println("Its start position is $index.")
        }
    }

    displaySubstringPosition("010000011", "11")
    displaySubstringPosition("010000011", "12")
}

使用场景

有这么一种场景可以使用,如请求后台返回了一个 UserCallback 对象,需要在界面显示这个 UserCallback 包含的一个 address 字符串,如果返回的 address 如果是 null 或空字符串则显示“未设置”

以前这种场景一般都是这样实现的:

val addr = UserCallback.address
textView.text = if (addr.isNullOrBlank()) "未设置" else addr

但使用 takeIftakeUnless 可以这样实现更为直接:

textView.text = UserCallback.address.takeUnless { it.isNullOrBlank() }?:"未设置"
 
// 或者使用takeIf的写法
// textView.text = UserCallback.address.takeIf { !it.isNullOrBlank() }?:"未设置"

你可能感兴趣的:(Kotlin takeIf 和 takeUnless)