我一直遵循http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-in-conditions的Kotlin文档,并尝试改编此示例,
val b = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
对于b = null
的情况。在IntelliJ Idea Kotlin项目中,我有一个app.kt
,其main()
函数定义为:
fun main() {
val b = null
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
}
但是,当我运行它时,出现两个编译错误:
Information:Kotlin: kotlinc-jvm 1.3.20 (JRE 11+28)
Information:2019-02-02 15:07 - Compilation completed with 2 errors and 0 warnings in 1 s 921 ms
/Users/kurtpeek/IdeaProjects/HelloWorld/src/app.kt
Error:(3, 24) Kotlin: Unresolved reference: length
Error:(4, 37) Kotlin: Unresolved reference: length
我了解即使第一个条件b.length
是b != null
,编译器仍在评估false
。这让我感到惊讶,因为我认为第一步是在需要时“短路”布尔表达式,然后调用b.length
“安全”。
例如,在Python中,您可以执行以下操作:
In [1]: "foo" == "bar" and what.the.heck
Out[1]: False
即使未定义what
,它仍然有效,因为and
不等于"foo"
,"bar"
停止了。
这真的是科特林的工作方式吗?似乎缺少Python的“短路”功能将是一个限制。
答案 0 :(得分:8)
Kotlin的&&
运算符将短路(就像Java一样),但仅在运行时会短路。您遇到的是一个编译时间错误。特别是在将Kotlin(或Java)与Python进行比较时,要记住的最大区别是Kotlin和Java是静态类型的,并且具有编译阶段。因此,如果类型不匹配,则会出现编译错误。
让我们一次浏览一下...
val b = "Kotlin"
if (b != null && b.length > 0) {
...
}
在这种情况下,Kotlin将正确推断出b
是类型String
,因为您已将其明确设置为String(“ Kotlin”)。在这里我们应该注意String
类型永远不能包含null。知道这一点,您的b != null
语句的if
部分是不必要的。但是,在评估完该变量(始终为真)之后,它将评估b.length
,因为b
是String
,因此具有length
属性。此示例应该可以很好地编译(我没有对其进行测试)。
然后下一个...
val b = null
if (b != null && b.length > 0) {
...
}
此代码将无法编译,让我们看看原因...
这段代码看起来确实非常相似,但有很大的不同。在这种情况下,因为您只是将b
设置为null
,所以Kotlin将推断b
是Nothing?
。它没有有关您希望b
成为哪种类型的信息,并且已将其设置为null(并且由于它是val
,因此它总是 为{{ 1}})。由于null
是b
,因此null
可以为空。
因此,鉴于此,当我们编译b
时,它将总是失败,因为b != null
永远不可能是不是b
的东西。可是等等!我们现在正在编译...,当我们遇到null
时,由于b.length
没有Nothing?
属性,因此Kotlin将抛出编译错误!
从本质上讲,通过将length
设置为b
而不提供类型提示,Kotlin将采用唯一的路径来推断类型-null
。
答案 1 :(得分:1)
在链接的文本中:“请注意,这仅在b是不可变的情况下有效(即在检查和用法之间未修改的局部变量,或者具有备用字段且不可覆盖的成员val)。”
val b=null
是不可变的,但是由于无法推断或存储null的类型,因此不能将其用作有效快捷方式的来源。
如果您将代码更改为可为空的类型,并将其设置为null,则可以使用。