简而言之,这是不可能的。
契约主要考虑方法的行为而不是值的属性。值的属性应该由类型系统而不是契约来处理。
是的,它可能会在未来实施。
这并不意味着如果类型系统可以处理某些事情,那么它就超出了合同的范围。
https://github.com/Kotlin/KEEP/blob/master/proposals/kotlin-contracts.md#scope-and-restrictions
备择方案
Null 在 Kotlin 的类型系统中得到了很好的处理,因此我们可以使用它来检查可空性。
智能铸造
使用智能铸造将消除对合同和hasDescription()
方法的需求。
fun nullCheckWhen(gadget: Gadget) {
when (val description = gadget.description) {
null -> println("description is null")
else -> println("description.length ${description.length}")
}
}
fun earlyReturn(gadget: Gadget) {
val description = gadget.description ?: return
println("description.length ${description.length}")
}
fun forcefulNullCheck(gadget: Gadget) {
val description = requireNotNull(gadget.description) {
"description must not be null"
}
println("description.length ${description.length}")
}
fun elvisScopeFunctionNullSafe(gadget: Gadget) {
gadget.widget?.description?.let { description ->
println("description.length ${description.length}")
}
}
这些有点笨拙,并且不像合同那样漂亮 - 但至少它们有效。
事实上,他们中的一些人使用 Kotlin Contracts,但他们当然只能对方法参数起作用。
Preconditions.kt
/**
* Throws an [IllegalArgumentException] if the [value] is null. Otherwise returns the not null value.
*/
@kotlin.internal.InlineOnly
public inline fun <T : Any> requireNotNull(value: T?): T {
contract {
returns() implies (value != null)
}
return requireNotNull(value) { "Required value was null." }
}
类型层次结构
我认为这种方法不适用于您的情况,但我想我会分享它,因为它可能有用。
如果description
在接口中定义为 a String?
,则Widget
可以实现description
为 non-nullable String
。这是因为在 Kotlin 中可空类型是不可空类型的超类型。的任何实现都description
可以选择为 beString?
或String
.
interface Component {
val description: String?
}
data class Widget(
override val description: String
) : Component
data class Greeble(
override val description: String?
) : Component
fun nullCheckGeneric(component: Component) {
when (component) {
is Widget ->
// no need for a null check
println("description.length ${component.description.length}")
is Greeble ->
// description is nullable
println("description.length ${component.description?.length}")
}
}