在String类型的可空接收器上只允许安全(?。)或非空断言(!!。)调用?

时间:2018-02-27 10:23:20

标签: kotlin

fun checkLengthA(str : String?): Int = if (str.isNullOrBlank()) 0 else str.length

“在String类型的可空接收器上只允许安全(?。)或非空的断言(!!。)调用?

所有空对象(或空)都被isNullOrBlank()捕获,因此str.length中的str对象永远不能为null(或为空)。这可以通过使用显式检查替换扩展功能来实现。

fun checkLengthB(str : String?): Int = if (str == null) 0 else str.length

或更简洁的表达:

fun checkLengthC(str : String?): Int = str?.length ?: 0

checkLengthB和checkLengthC都可以顺利运行。

让我们从checkLengthA中删除可空类型以避免编译错误,如上所示:

fun checkLengthA(str : String): Int = if (str.isNullOrBlank()) 0 else str.length

现在,我们只允许使用String类型的非null参数,所以如果我们期望一些null类型,那么我们必须把“?”回来。

看起来编译器不理解str类型的str在运行str.length和扩展函数时永远不会计算为null,但是如果我们在if-else中使用(str == null)它将编译没有问题言。

任何人都可以解释为什么会这样吗?

1 个答案:

答案 0 :(得分:4)

编译器无法证明在isNullOrBlank求值为false之后,该参数不能为空。 isNullOrBlank只是一个普通方法,相同的参数可以应用于检查参数是否为null的任意数量的函数。如果有人将isNullOrBlank的实施更改为始终返回false

,该怎么办?

arg == null的情况下,编译器知道这必须意味着参数不为null,因为,这正是== null的意思,语法和字面意思

请注意,== null并不总是导致安全转换,例如,当被检查的变量是属性时。

在这种情况下:

str?.length ?: 0

没有涉及智能演员阵容。

str?.lengthInt?,使用猫王操作符?:,您最终会得到Int

有趣的是,the implementation of isNullOrBlank包含此contract

contract {
    returns(false) implies (this@isNullOrBlank != null)
}

所以也许这会得到支持。