示例:
class Object(val value: Int?) {
fun doesNotContainNull() = value != null
}
Object obj = Object(randomValue)
然后,当我使用此对象时,我可以这样做一个零检查:
if (obj.value != null) {
passNonNullableValue(obj.value) // compiles
}
或喜欢这个
if (obj.doesNotContainNull()) {
passNonNullableValue(obj.value) // does not compile
}
为什么编译器抱怨第二个狙击手?不能解决该值不能无效吗?还是我错过了什么?
这是通过Kotlin合同 - Kotlin 1.3的实验特征,以增强智能演员的支持。
这是contract
的一个简单示例:
@ExperimentalContracts
fun Object?.isNotNull(): Boolean {
contract {
// If I return "true", then it means that I am not null
returns(true) implies (this@isNotNull != null)
}
return this != null
}
if (obj.isNotNull())
print(obj.value) // smart-cast applied.
现在,我在这里说,因为合同的使用有一些局限性。只有顶级功能支持它们。这意味着您必须创建Object
类的扩展名。另一个限制是,我们要在此处检查Object.value
的无效性,而不是Object
本身。合同定义不支持这。因此,即使看起来很理想,以下内容也没有编译:
@ExperimentalContracts
fun Object.doesNotContainNull(): Boolean {
contract {
// The following line gives an error:
// Error in contract description: only references to parameters are allowed in contract description.
returns(true) implies (this@doesNotContainNull.value != null) }
return value != null
}
正如错误所暗示的那样,我们可以参考合同描述中的参数。因此,我们可以提出一个解决方法,在该解决方案中,我们将value
作为参数传递。最后,该函数看起来如下:
@ExperimentalContracts
fun Object.doesNotContainNull(value: Int?): Boolean {
contract {
returns(true) implies (value != null)
}
return value != null
}
if (obj.doesNotContainNull(obj.value)) {
passNonNullableValue(obj.value) // smart cast applied!
}
即使这种方法有效,这也很危险,因为呼叫者可能并不总是将obj.value
作为参数传递。因此,如果支票失败,我们希望确保条件并丢下运行时错误。
@ExperimentalContracts
fun Object.doesNotContainNull(value: Int?): Boolean {
contract {
// "If I return true, then it means that $value is not null."
returns(true) implies (value != null)
}
if(value != this.value)
throw IllegalArgumentException("$value must be ${this.value}")
return value != null
}
完整的示例可以在此操场上进行。
kotlin 编译器不知道调用 doesNotContainNull()
的含义。为了提供此信息,引入了kotlin.contracts
。尽管此API仍然有一些快捷方式,但您可以使用sealed class
方法将其抽象。
sealed class Object {
abstract val value: Int?
class NotNull(override val value: Int) : Object()
object Null : Object() {
override val value: Int? = null
}
companion object {
operator fun invoke(value: Int?) = if (value == null)
Object.Null else Object.NotNull(value)
}
}
fun Object.doesNotContainNull(): Boolean {
contract {
returns(true) implies (this@doesNotContainNull is Object.NotNull)
}
return value != null
}
可以像您一样实现一切,就可以使用。
有点冗长。,但最终使用?.let
可能更清楚地阅读和理解。
obj.value?.let {
passNonNullableValue(it)
}