rex*_*ar5 9 kotlin kotlin-null-safety kotlin-contracts
我正在尝试编写一个扩展函数,true如果值不null为 0 则返回,并使用契约向编译器保证,如果我返回true,则该值不为空。但是,它似乎不适用于智能投射。当我尝试将值传递给采用非 nullable 的函数时,它仍然无法编译Long。
我尝试编译这段代码,但它不起作用。我希望将 a从 aid智能转换为a ,因为合约保证如果返回则传入的值不为空。LongLong?isValidIdtrueLong?
正如您所看到的,该属性是不可变的,所以我认为这不是问题。我还在下面添加了更多代码,因为问题似乎特定于扩展函数。当我将 ID 作为传统参数传递时它会起作用。
fun test() {
val id: Long? = null //5L
if (id.isValidID()) {
// It won't compile because the compiler says that id is a Long?
// instead of smart casting it to a Long. doWithId requires a Long.
doWithId(id)
}
}
fun doWithId(id: Long) {}
@OptIn(ExperimentalContracts::class)
fun Long?.isValidID(): Boolean {
contract { returns(true) implies (this@isValidID != null) }
return this != null && this != 0L
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
编辑: 哦!当它不是扩展函数时它可以工作。有人知道如何使扩展功能发挥作用吗?
fun test() {
val id: Long? = null
if (isValidID(id)) {
// This compiles now that I pass ID as a param instead of
// passing it in an extension function.
doWithId(id)
}
}
fun doWithId(id: Long) {}
@OptIn(ExperimentalContracts::class)
fun isValidID(id: Long?): Boolean {
contract { returns(true) implies (id != null) }
return id != null && id != 0L
}
Run Code Online (Sandbox Code Playgroud)
我想我明白发生了什么。这对您来说不适用于扩展函数的原因更多地与编译器如何解释代码有关,而不是与扩展函数本身有关。我的假设是,当编译器查看扩展函数时,它只会看到:
if (id.isValidID()) {
doWithId(id)
}
Run Code Online (Sandbox Code Playgroud)
我们可以说这样我们就可以确定 id 不为空。但是,编译器可能只将此视为对函数的调用,该函数对于确定 id 的值是否为 null 没有可预测的影响。所以编译器无法判断id是否为null。
在传统情况下,编译器会看到:
if (isValidID(id)) {
doWithId(id)
}
Run Code Online (Sandbox Code Playgroud)
对于编译器来说,仅当函数结果为 true 时才会进行验证isValidID,但这样,编译器也会看到返回值取决于评估 id 不为空。这样,它就可以直接执行从Long?到 的智能广播Long。
它非常语义化,但它符合我对编译器的期望。我不知道编译器是否会很快改变这一点,但扩展函数确实只存在这么长时间,因此为了同时解决这个问题,我们可以使用这样的东西:
fun test() {
val id: Long? = 5L
if (id.isValidID()) {
doWithId(id!!)
}
}
Run Code Online (Sandbox Code Playgroud)
!!但我总是不喜欢这样使用:
fun test() {
val id: Long? = 5L
if (id.isValidID()) {
doWithId(requireNotNull(id))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
454 次 |
| 最近记录: |