可空类型的扩展
有时事情并不是看起来的那样。
s?.f()
暗示了 s
是可空的,否则你可以简单地调用 s.f()
。类似地,t.f()
看起来似乎是 t
是非空的,因为 Kotlin 不要求使用安全调用或编程检查。然而,t
并不一定是非空的。
Kotlin 标准库提供了 String
的扩展函数,包括:
isNullOrEmpty()
:检查接收者String
是否为null
或为空。isNullOrBlank()
:执行与isNullOrEmpty()
相同的检查,并且允许接收者String
仅由空白字符组成,包括制表符(\t
)和换行符(\n
)。
下面是这些函数的基本测试:
// NullableExtensions/StringIsNullOr.kt
import atomictest.eq
fun main() {
val s1: String? = null
s1.isNullOrEmpty() eq true
s1.isNullOrBlank() eq true
val s2 = ""
s2.isNullOrEmpty() eq true
s2.isNullOrBlank() eq true
val s3: String = " \t\n"
s3.isNullOrEmpty() eq false
s3.isNullOrBlank() eq true
}
函数的名称表明它们适用于可空类型。然而,即使 s1
是可空的,您也可以调用 isNullOrEmpty()
或 isNullOrBlank()
而不使用安全调用或显式检查。这是因为这些函数是可空类型 String?
的扩展函数。
我们可以将 isNullOrEmpty()
重写为一个非扩展函数,该函数以可空 String s
作为参数:
// NullableExtensions/NullableParameter.kt
package nullableextensions
import atomictest.eq
fun isNullOrEmpty(s: String?): Boolean =
s == null || s.isEmpty()
fun main() {
isNullOrEmpty(null) eq true
isNullOrEmpty("") eq true
}
由于 s
是可空的,我们明确地检查了 null
或空。表达式 s == null || s.isEmpty()
使用了短路求值:如果表达式的第一部分是 true
,则不会评估表达式的其余部分,从而防止了 null
指针异常。
扩展函数使用 this
来表示接收者(被扩展类型的对象)。为了使接收者可空,将 ?
添加到被扩展类型的类型中:
// NullableExtensions/NullableExtension.kt
package nullableextensions
import atomictest.eq
fun String?.isNullOrEmpty(): Boolean =
this == null || isEmpty()
fun main() {
"".isNullOrEmpty() eq true
}
isNullOrEmpty()
作为扩展函数更易读。
- -
在使用可空类型的扩展时要小心。它们非常适用于简单的情况,例如 isNullOrEmpty()
和 isNullOrBlank()
,尤其是使用表达接收者可能是 null
的自我解释性名称。一般来说,最好声明常规(非可空)的扩展。安全调用和显式检查可以澄清接收者的可空性,而针对可空类型的扩展可能会隐藏可空性,令代码的读者(可能是“未来的你”)困惑。
练习和答案可以在 www.AtomicKotlin.com 找到。